BasicObjCFoundationChecks.cpp revision 921ddc4e7ef35d77965205d91582c356cb54f5ef
199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*-- 299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// 399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// The LLVM Compiler Infrastructure 499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// 599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// This file is distributed under the University of Illinois Open Source 699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// License. See LICENSE.TXT for details. 799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// 899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// 1099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// This file defines BasicObjCFoundationChecks, a class that encapsulates 1199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// a set of simple checks to run on Objective-C code using Apple's Foundation 1299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// classes. 1399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// 1499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 1599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 16527556184b276c545be1355ad596fce29a0400fbTed Kremenek#include "BasicObjCFoundationChecks.h" 17527556184b276c545be1355ad596fce29a0400fbTed Kremenek 1899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "clang/Analysis/PathSensitive/ExplodedGraph.h" 1999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" 2078d46242e3351484c2b773f5610beba5d316914bTed Kremenek#include "clang/Analysis/PathSensitive/GRExprEngine.h" 214adc81e540b874bafa15715fd2c5cb662463debdTed Kremenek#include "clang/Analysis/PathSensitive/GRState.h" 22f1ae705460552655fe7275327804444c62e86baeTed Kremenek#include "clang/Analysis/PathSensitive/BugReporter.h" 239e24049bef26b6289cce9ac9b483c5cbb096e3aeTed Kremenek#include "clang/Analysis/PathSensitive/MemRegion.h" 2499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "clang/Analysis/PathDiagnostic.h" 2550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek#include "clang/Analysis/PathSensitive/CheckerVisitor.h" 2678d46242e3351484c2b773f5610beba5d316914bTed Kremenek#include "clang/Analysis/LocalCheckers.h" 27c4a1dea2dc56bd1357ec91b829a0b9e68229a13eDaniel Dunbar#include "clang/AST/DeclObjC.h" 2899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "clang/AST/Expr.h" 29f494b579b22f9950f5af021f0bf9879a91bb8b41Steve Naroff#include "clang/AST/ExprObjC.h" 3099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "clang/AST/ASTContext.h" 3199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "llvm/Support/Compiler.h" 3299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 3399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekusing namespace clang; 34f1ae705460552655fe7275327804444c62e86baeTed Kremenek 3514108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffstatic const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { 3614108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff const Expr* Receiver = ME->getReceiver(); 371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 38f1ae705460552655fe7275327804444c62e86baeTed Kremenek if (!Receiver) 39f1ae705460552655fe7275327804444c62e86baeTed Kremenek return NULL; 401eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 4114108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff if (const ObjCObjectPointerType *PT = 42183700f494ec9b6701b6efe82bcb25f4c79ba561John McCall Receiver->getType()->getAs<ObjCObjectPointerType>()) 4314108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff return PT->getInterfaceType(); 44c1ff3cd5fe4436bb14309fdc5ee7e1c2b702b7c3Ted Kremenek 45c1ff3cd5fe4436bb14309fdc5ee7e1c2b702b7c3Ted Kremenek return NULL; 46f1ae705460552655fe7275327804444c62e86baeTed Kremenek} 47f1ae705460552655fe7275327804444c62e86baeTed Kremenek 4814108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffstatic const char* GetReceiverNameType(const ObjCMessageExpr* ME) { 49e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME)) 50e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar return ReceiverType->getDecl()->getIdentifier()->getNameStart(); 51e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar return NULL; 52f1ae705460552655fe7275327804444c62e86baeTed Kremenek} 53f1ae705460552655fe7275327804444c62e86baeTed Kremenek 5499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremeneknamespace { 55b344f91f00021b88e365a4a38502090c3b0cef12Ted Kremenek 56cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenekclass VISIBILITY_HIDDEN APIMisuse : public BugType { 57f1ae705460552655fe7275327804444c62e86baeTed Kremenekpublic: 58cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {} 59f1ae705460552655fe7275327804444c62e86baeTed Kremenek}; 601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 6199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekclass VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { 62cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek APIMisuse *BT; 63cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BugReporter& BR; 64e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek ASTContext &Ctx; 651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 66d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar bool isNSString(const ObjCInterfaceType *T, llvm::StringRef suffix); 67031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME); 681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 691eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump void Warn(ExplodedNode* N, const Expr* E, const std::string& s); 70031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu void WarnNilArg(ExplodedNode* N, const Expr* E); 711eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 72031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu bool CheckNilArg(ExplodedNode* N, unsigned Arg); 7399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 7499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekpublic: 751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br) 7623ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek : BT(0), BR(br), Ctx(ctx) {} 771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 78c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bool Audit(ExplodedNode* N, GRStateManager&); 791eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpprivate: 811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump void WarnNilArg(ExplodedNode* N, const ObjCMessageExpr* ME, unsigned Arg) { 82cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek std::string sbuf; 83cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek llvm::raw_string_ostream os(sbuf); 84cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek os << "Argument to '" << GetReceiverNameType(ME) << "' method '" 85cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek << ME->getSelector().getAsString() << "' cannot be nil."; 861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 87cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // Lazily create the BugType object for NilArg. This will be owned 88cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // by the BugReporter object 'BR' once we call BR.EmitWarning. 89cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek if (!BT) BT = new APIMisuse("nil argument"); 901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 91cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N); 92cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek R->addRange(ME->getArg(Arg)->getSourceRange()); 93cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BR.EmitReport(R); 94f1ae705460552655fe7275327804444c62e86baeTed Kremenek } 9599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek}; 961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 9799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} // end anonymous namespace 9899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 9999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 100527556184b276c545be1355ad596fce29a0400fbTed KremenekGRSimpleAPICheck* 10123ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenekclang::CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR) { 1021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return new BasicObjCFoundationChecks(Ctx, BR); 103527556184b276c545be1355ad596fce29a0400fbTed Kremenek} 104527556184b276c545be1355ad596fce29a0400fbTed Kremenek 1054ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek 10699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 107c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xubool BasicObjCFoundationChecks::Audit(ExplodedNode* N, 1084adc81e540b874bafa15715fd2c5cb662463debdTed Kremenek GRStateManager&) { 1091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1105f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const ObjCMessageExpr* ME = 1114ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 1124ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek 11314108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); 1141eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 11599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek if (!ReceiverType) 116f74279447d4ad0a0c0f2e6e6740d5a0f4c242e0cNuno Lopes return false; 1171eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 118d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar if (isNSString(ReceiverType, 11901eb9b9683535d8a65c704ad2c545903409e2d36Daniel Dunbar ReceiverType->getDecl()->getIdentifier()->getName())) 12099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek return AuditNSString(N, ME); 12199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 122f74279447d4ad0a0c0f2e6e6740d5a0f4c242e0cNuno Lopes return false; 12399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} 12499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 1251c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xustatic inline bool isNil(SVal X) { 1261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return isa<loc::ConcreteInt>(X); 127e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek} 128e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek 12999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 13099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// Error reporting. 13199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 13299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 133031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xubool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) { 1345f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const ObjCMessageExpr* ME = 1354ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 1361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1375f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const Expr * E = ME->getArg(Arg); 1381eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 13923ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek if (isNil(N->getState()->getSVal(E))) { 140f1ae705460552655fe7275327804444c62e86baeTed Kremenek WarnNilArg(N, ME, Arg); 1414ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return true; 1424ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek } 1431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1444ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return false; 1454ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek} 1464ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek 14799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 14899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// NSString checking. 14999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 15099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 15114108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffbool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T, 152d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar llvm::StringRef ClassName) { 153d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar return ClassName == "NSString" || ClassName == "NSMutableString"; 15499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} 15599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 1561eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpbool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N, 1575f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const ObjCMessageExpr* ME) { 1581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 15999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek Selector S = ME->getSelector(); 1601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 16199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek if (S.isUnarySelector()) 16299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek return false; 16399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 16499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek // FIXME: This is going to be really slow doing these checks with 16599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek // lexical comparisons. 1661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 167077bf5e2f48acfa9e7d69429b6e4ba86ea14896dChris Lattner std::string name = S.getAsString(); 1689b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek assert (!name.empty()); 1699b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek const char* cstr = &name[0]; 1709b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek unsigned len = name.size(); 1711eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1729b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek switch (len) { 1739b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek default: 1749b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek break; 1751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump case 8: 1764ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "compare:")) 1774ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 1781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1794ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek break; 1801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1818730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek case 15: 1828730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek // FIXME: Checking for initWithFormat: will not work in most cases 1838730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek // yet because [NSString alloc] returns id, not NSString*. We will 1848730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek // need support for tracking expected-type information in the analyzer 1858730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek // to find these errors. 1868730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek if (!strcmp(cstr, "initWithFormat:")) 1878730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek return CheckNilArg(N, 0); 1881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1898730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek break; 1901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1914ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 16: 1924ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "compare:options:")) 1934ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 1941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1954ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek break; 1961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1974ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 22: 1984ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "compare:options:range:")) 1994ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 2001eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2014ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek break; 2021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2034ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 23: 2041eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2054ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "caseInsensitiveCompare:")) 2064ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 2071eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2089b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek break; 2098730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek 2104ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 29: 2114ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "compare:options:range:locale:")) 2124ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 2131eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2141eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump break; 2151eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2164ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 37: 2174ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:")) 2184ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 2191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump break; 22199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek } 2221eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 22399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek return false; 22499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} 22504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 22604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek//===----------------------------------------------------------------------===// 22704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek// Error reporting. 22804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek//===----------------------------------------------------------------------===// 22904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 23004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremeneknamespace { 23104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 23204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekclass VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck { 233cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek APIMisuse* BT; 2341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 23504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: Either this should be refactored into GRSimpleAPICheck, or 23604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // it should always be passed with a call to Audit. The latter 23704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // approach makes this class more stateless. 23804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek ASTContext& Ctx; 23904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek IdentifierInfo* II; 240cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BugReporter& BR; 24123ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek 24204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekpublic: 2431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump AuditCFNumberCreate(ASTContext& ctx, BugReporter& br) 24423ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek : BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), BR(br){} 2451eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 246cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek ~AuditCFNumberCreate() {} 2471eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 248c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bool Audit(ExplodedNode* N, GRStateManager&); 2491eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 25004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekprivate: 251c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu void AddError(const TypedRegion* R, const Expr* Ex, ExplodedNode *N, 2521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); 25304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}; 25404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} // end anonymous namespace 25504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 25604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekenum CFNumberType { 25704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt8Type = 1, 25804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt16Type = 2, 25904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt32Type = 3, 26004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt64Type = 4, 26104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberFloat32Type = 5, 26204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberFloat64Type = 6, 26304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberCharType = 7, 26404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberShortType = 8, 26504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberIntType = 9, 26604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberLongType = 10, 26704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberLongLongType = 11, 26804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberFloatType = 12, 26904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberDoubleType = 13, 27004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberCFIndexType = 14, 27104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberNSIntegerType = 15, 27204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberCGFloatType = 16 27304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}; 27404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 27504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremeneknamespace { 27604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek template<typename T> 27704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek class Optional { 27804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek bool IsKnown; 27904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek T Val; 28004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek public: 28104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek Optional() : IsKnown(false), Val(0) {} 28204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek Optional(const T& val) : IsKnown(true), Val(val) {} 2831eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 28404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek bool isKnown() const { return IsKnown; } 28504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 28604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek const T& getValue() const { 28704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek assert (isKnown()); 28804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return Val; 28904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek } 29004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 29104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek operator const T&() const { 29204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return getValue(); 29304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek } 29404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek }; 29504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 29604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 29704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekstatic Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) { 29804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; 2991eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 30004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (i < kCFNumberCharType) 30104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return FixedSize[i-1]; 3021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 30304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek QualType T; 3041eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 30504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek switch (i) { 30604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberCharType: T = Ctx.CharTy; break; 30704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberShortType: T = Ctx.ShortTy; break; 30804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberIntType: T = Ctx.IntTy; break; 30904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberLongType: T = Ctx.LongTy; break; 31004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberLongLongType: T = Ctx.LongLongTy; break; 31104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberFloatType: T = Ctx.FloatTy; break; 31204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberDoubleType: T = Ctx.DoubleTy; break; 31304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberCFIndexType: 31404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberNSIntegerType: 31504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberCGFloatType: 3161eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // FIXME: We need a way to map from names to Type*. 31704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek default: 31804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return Optional<uint64_t>(); 31904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek } 3201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 32104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return Ctx.getTypeSize(T); 32204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 32304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 32404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek#if 0 32504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekstatic const char* GetCFNumberTypeStr(uint64_t i) { 32604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek static const char* Names[] = { 32704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt8Type", 32804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt16Type", 32904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt32Type", 33004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt64Type", 33104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberFloat32Type", 33204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberFloat64Type", 33304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberCharType", 33404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberShortType", 33504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberIntType", 33604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberLongType", 33704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberLongLongType", 33804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberFloatType", 33904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberDoubleType", 34004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberCFIndexType", 34104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberNSIntegerType", 34204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberCGFloatType" 34304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek }; 3441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 34504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType"; 34604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 34704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek#endif 34804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 3491eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpbool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){ 3505f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const CallExpr* CE = 3515f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 3521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump const Expr* Callee = CE->getCallee(); 3531eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump SVal CallV = N->getState()->getSVal(Callee); 354369f447eded97e6048ced02c0c2be3842f61fc1cZhongxing Xu const FunctionDecl* FD = CallV.getAsFunctionDecl(); 35504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 356369f447eded97e6048ced02c0c2be3842f61fc1cZhongxing Xu if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3) 35704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 35904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // Get the value of the "theType" argument. 36023ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek SVal TheTypeVal = N->getState()->getSVal(CE->getArg(1)); 3611eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 36204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: We really should allow ranges of valid theType values, and 36304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // bifurcate the state appropriately. 3641c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xu nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal); 3651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 36604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (!V) 36704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 36904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t NumberKind = V->getValue().getLimitedValue(); 37004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind); 3711eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 37204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: In some cases we can emit an error. 37304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (!TargetSize.isKnown()) 37404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 37604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // Look at the value of the integer being passed by reference. Essentially 37704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // we want to catch cases where the value passed in is not equal to the 37804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // size of the type being created. 37923ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek SVal TheValueExpr = N->getState()->getSVal(CE->getArg(2)); 3801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 38104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: Eventually we should handle arbitrary locations. We can do this 38204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // by having an enhanced memory model that does low-level typing. 3831c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xu loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr); 38404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 38504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (!LV) 38604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 388479529e679957fbb92b56e116e3c86734429331eZhongxing Xu const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts()); 3895e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek 3905e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek if (!R) 3915e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek return false; 3925e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek 393a82d8aa5b3b3d24998b4d98b9f45a43cc84cac6fZhongxing Xu QualType T = Ctx.getCanonicalType(R->getValueType(Ctx)); 3941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 39504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: If the pointee isn't an integer type, should we flag a warning? 39604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // People can do weird stuff with pointers. 3971eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3981eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (!T->isIntegerType()) 39904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 4001eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 40104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t SourceSize = Ctx.getTypeSize(T); 4021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 40304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // CHECK: is SourceSize == TargetSize 4041eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 40504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (SourceSize == TargetSize) 40604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 4071eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 4089e24049bef26b6289cce9ac9b483c5cbb096e3aeTed Kremenek AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind); 4091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 41004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: We can actually create an abstract "CFNumber" object that has 41104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // the bits initialized to the provided values. 41204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return SourceSize < TargetSize; 41304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 41404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 4155f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenekvoid AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex, 416c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu ExplodedNode *N, 41704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t SourceSize, uint64_t TargetSize, 41804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t NumberKind) { 4191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 420cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek std::string sbuf; 421cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek llvm::raw_string_ostream os(sbuf); 4221eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 42304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek os << (SourceSize == 8 ? "An " : "A ") 42404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek << SourceSize << " bit integer is used to initialize a CFNumber " 42504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "object that represents " 42604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek << (TargetSize == 8 ? "an " : "a ") 4271eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump << TargetSize << " bit integer. "; 42804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 42904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (SourceSize < TargetSize) 43004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek os << (TargetSize - SourceSize) 4311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump << " bits of the CFNumber value will be garbage." ; 43204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek else 43304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek os << (SourceSize - TargetSize) 43404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek << " bits of the input integer will be lost."; 4351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 436cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // Lazily create the BugType object. This will be owned 437cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // by the BugReporter object 'BR' once we call BR.EmitWarning. 438cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate"); 439cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N); 440cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek report->addRange(Ex->getSourceRange()); 441cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BR.EmitReport(report); 44204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 44304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 44404bc87683acacce119967dfa5f7c35b4ecef012aTed KremenekGRSimpleAPICheck* 4451eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpclang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) { 44623ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek return new AuditCFNumberCreate(Ctx, BR); 44704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 44804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 44978d46242e3351484c2b773f5610beba5d316914bTed Kremenek//===----------------------------------------------------------------------===// 45079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek// CFRetain/CFRelease auditing for null arguments. 45179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===// 45279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 45379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremeneknamespace { 45479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenekclass VISIBILITY_HIDDEN AuditCFRetainRelease : public GRSimpleAPICheck { 45579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek APIMisuse *BT; 4561eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 45779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // FIXME: Either this should be refactored into GRSimpleAPICheck, or 45879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // it should always be passed with a call to Audit. The latter 45979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // approach makes this class more stateless. 46079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek ASTContext& Ctx; 46179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek IdentifierInfo *Retain, *Release; 46279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BugReporter& BR; 4631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 46479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenekpublic: 4651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump AuditCFRetainRelease(ASTContext& ctx, BugReporter& br) 46679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek : BT(0), Ctx(ctx), 46779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek Retain(&Ctx.Idents.get("CFRetain")), Release(&Ctx.Idents.get("CFRelease")), 46879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BR(br){} 4691eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 47079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek ~AuditCFRetainRelease() {} 4711eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 472c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bool Audit(ExplodedNode* N, GRStateManager&); 47379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek}; 47479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} // end anonymous namespace 47579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 47679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 477c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xubool AuditCFRetainRelease::Audit(ExplodedNode* N, GRStateManager&) { 4785f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 4791eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 48079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // If the CallExpr doesn't have exactly 1 argument just give up checking. 48179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (CE->getNumArgs() != 1) 48279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 4831eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 48479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // Check if we called CFRetain/CFRelease. 48579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek const GRState* state = N->getState(); 48679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek SVal X = state->getSVal(CE->getCallee()); 48779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek const FunctionDecl* FD = X.getAsFunctionDecl(); 4881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 48979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (!FD) 49079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 4911eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 4921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump const IdentifierInfo *FuncII = FD->getIdentifier(); 49379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (!(FuncII == Retain || FuncII == Release)) 49479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 4951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 49679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // Finally, check if the argument is NULL. 49779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // FIXME: We should be able to bifurcate the state here, as a successful 49879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // check will result in the value not being NULL afterwards. 49979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // FIXME: Need a way to register vistors for the BugReporter. Would like 50079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // to benefit from the same diagnostics that regular null dereference 50179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // reporting has. 50279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (state->getStateManager().isEqual(state, CE->getArg(0), 0)) { 50379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (!BT) 50479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BT = new APIMisuse("null passed to CFRetain/CFRelease"); 5051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 50679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek const char *description = (FuncII == Retain) 50779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek ? "Null pointer argument in call to CFRetain" 50879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek : "Null pointer argument in call to CFRelease"; 50979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 51079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek RangedBugReport *report = new RangedBugReport(*BT, description, N); 51179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek report->addRange(CE->getArg(0)->getSourceRange()); 51279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BR.EmitReport(report); 51379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return true; 51479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek } 51579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 51679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 51779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} 5181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 52079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted KremenekGRSimpleAPICheck* 5211eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpclang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) { 52279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return new AuditCFRetainRelease(Ctx, BR); 52379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} 52479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 52579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===// 52650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek// Check for sending 'retain', 'release', or 'autorelease' directly to a Class. 52750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek//===----------------------------------------------------------------------===// 52850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 52950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremeneknamespace { 53050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenekclass VISIBILITY_HIDDEN ClassReleaseChecker : 53150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek public CheckerVisitor<ClassReleaseChecker> { 53250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector releaseS; 53350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector retainS; 53450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector autoreleaseS; 53550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector drainS; 53650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek BugType *BT; 53750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenekpublic: 53850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek ClassReleaseChecker(ASTContext &Ctx) 53950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek : releaseS(GetNullarySelector("release", Ctx)), 54050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek retainS(GetNullarySelector("retain", Ctx)), 54150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek autoreleaseS(GetNullarySelector("autorelease", Ctx)), 54250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek drainS(GetNullarySelector("drain", Ctx)), 54350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek BT(0) {} 54450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 54550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek static void *getTag() { static int x = 0; return &x; } 54650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 54750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); 54850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek}; 54950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek} 55050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 55150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenekvoid ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, 55250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek const ObjCMessageExpr *ME) { 55350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 55450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek const IdentifierInfo *ClsName = ME->getClassName(); 55550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek if (!ClsName) 55650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek return; 55750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 55850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector S = ME->getSelector(); 559921ddc4e7ef35d77965205d91582c356cb54f5efBenjamin Kramer if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) 56050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek return; 56150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 56250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek if (!BT) 56350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek BT = new APIMisuse("message incorrectly sent to class instead of class " 56450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek "instance"); 56550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 56650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek ExplodedNode *N = C.GenerateNode(ME, C.getState(), false); 56750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek if (!N) 56850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek return; 56950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 57050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek C.addTransition(N); 57150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 57250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek llvm::SmallString<200> buf; 57350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek llvm::raw_svector_ostream os(buf); 57450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 57550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek os << "The '" << S.getAsString() << "' message should be sent to instances " 57650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek "of class '" << ClsName->getName() 57750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek << "' and not the class directly"; 57850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 57950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); 58050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek report->addRange(ME->getSourceRange()); 58150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek C.EmitReport(report); 58250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek} 58350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 58450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek//===----------------------------------------------------------------------===// 58578d46242e3351484c2b773f5610beba5d316914bTed Kremenek// Check registration. 58679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===// 58778d46242e3351484c2b773f5610beba5d316914bTed Kremenek 5885ab128b02d3b10413fb30738ec9f401dcfb47252Zhongxing Xuvoid clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) { 58978d46242e3351484c2b773f5610beba5d316914bTed Kremenek ASTContext& Ctx = Eng.getContext(); 590cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BugReporter &BR = Eng.getBugReporter(); 59178d46242e3351484c2b773f5610beba5d316914bTed Kremenek 59223ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, BR), 59378d46242e3351484c2b773f5610beba5d316914bTed Kremenek Stmt::ObjCMessageExprClass); 5941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR), Stmt::CallExprClass); 59579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass); 5961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5975ab128b02d3b10413fb30738ec9f401dcfb47252Zhongxing Xu RegisterNSErrorChecks(BR, Eng, D); 59854cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek RegisterNSAutoreleasePoolChecks(Eng); 59950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Eng.registerCheck(new ClassReleaseChecker(Ctx)); 60078d46242e3351484c2b773f5610beba5d316914bTed Kremenek} 601