BasicObjCFoundationChecks.cpp revision 2550d70aabb5f603e8f74cc5fb6a69a7af5b51f3
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 3299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekusing namespace clang; 33f1ae705460552655fe7275327804444c62e86baeTed Kremenek 3414108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffstatic const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { 3514108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff const Expr* Receiver = ME->getReceiver(); 361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 37f1ae705460552655fe7275327804444c62e86baeTed Kremenek if (!Receiver) 38f1ae705460552655fe7275327804444c62e86baeTed Kremenek return NULL; 391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 4014108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff if (const ObjCObjectPointerType *PT = 41183700f494ec9b6701b6efe82bcb25f4c79ba561John McCall Receiver->getType()->getAs<ObjCObjectPointerType>()) 4214108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff return PT->getInterfaceType(); 43c1ff3cd5fe4436bb14309fdc5ee7e1c2b702b7c3Ted Kremenek 44c1ff3cd5fe4436bb14309fdc5ee7e1c2b702b7c3Ted Kremenek return NULL; 45f1ae705460552655fe7275327804444c62e86baeTed Kremenek} 46f1ae705460552655fe7275327804444c62e86baeTed Kremenek 4714108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffstatic const char* GetReceiverNameType(const ObjCMessageExpr* ME) { 48e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME)) 49e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar return ReceiverType->getDecl()->getIdentifier()->getNameStart(); 50e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar return NULL; 51f1ae705460552655fe7275327804444c62e86baeTed Kremenek} 52f1ae705460552655fe7275327804444c62e86baeTed Kremenek 5399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremeneknamespace { 54b344f91f00021b88e365a4a38502090c3b0cef12Ted Kremenek 55ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass APIMisuse : public BugType { 56f1ae705460552655fe7275327804444c62e86baeTed Kremenekpublic: 57cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {} 58f1ae705460552655fe7275327804444c62e86baeTed Kremenek}; 591eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 60ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass BasicObjCFoundationChecks : public GRSimpleAPICheck { 61cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek APIMisuse *BT; 62cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BugReporter& BR; 63e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek ASTContext &Ctx; 641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 65d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar bool isNSString(const ObjCInterfaceType *T, llvm::StringRef suffix); 66031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME); 671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump void Warn(ExplodedNode* N, const Expr* E, const std::string& s); 69031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu void WarnNilArg(ExplodedNode* N, const Expr* E); 701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 71031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu bool CheckNilArg(ExplodedNode* N, unsigned Arg); 7299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 7399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekpublic: 741eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br) 7523ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek : BT(0), BR(br), Ctx(ctx) {} 761eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 77c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bool Audit(ExplodedNode* N, GRStateManager&); 781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 791eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpprivate: 801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump void WarnNilArg(ExplodedNode* N, const ObjCMessageExpr* ME, unsigned Arg) { 81cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek std::string sbuf; 82cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek llvm::raw_string_ostream os(sbuf); 83cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek os << "Argument to '" << GetReceiverNameType(ME) << "' method '" 84cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek << ME->getSelector().getAsString() << "' cannot be nil."; 851eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 86cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // Lazily create the BugType object for NilArg. This will be owned 87cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // by the BugReporter object 'BR' once we call BR.EmitWarning. 88cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek if (!BT) BT = new APIMisuse("nil argument"); 891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 904988a9a278c50fddf46d38331e4a136a91487b7dBenjamin Kramer RangedBugReport *R = new RangedBugReport(*BT, os.str(), N); 91cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek R->addRange(ME->getArg(Arg)->getSourceRange()); 92cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BR.EmitReport(R); 93f1ae705460552655fe7275327804444c62e86baeTed Kremenek } 9499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek}; 951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 9699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} // end anonymous namespace 9799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 9899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 99527556184b276c545be1355ad596fce29a0400fbTed KremenekGRSimpleAPICheck* 10023ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenekclang::CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR) { 1011eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return new BasicObjCFoundationChecks(Ctx, BR); 102527556184b276c545be1355ad596fce29a0400fbTed Kremenek} 103527556184b276c545be1355ad596fce29a0400fbTed Kremenek 1044ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek 10599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 106c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xubool BasicObjCFoundationChecks::Audit(ExplodedNode* N, 1074adc81e540b874bafa15715fd2c5cb662463debdTed Kremenek GRStateManager&) { 1081eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1095f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const ObjCMessageExpr* ME = 1104ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 1114ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek 11214108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); 1131eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 11499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek if (!ReceiverType) 115f74279447d4ad0a0c0f2e6e6740d5a0f4c242e0cNuno Lopes return false; 1161eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 117d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar if (isNSString(ReceiverType, 11801eb9b9683535d8a65c704ad2c545903409e2d36Daniel Dunbar ReceiverType->getDecl()->getIdentifier()->getName())) 11999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek return AuditNSString(N, ME); 12099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 121f74279447d4ad0a0c0f2e6e6740d5a0f4c242e0cNuno Lopes return false; 12299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} 12399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 1241c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xustatic inline bool isNil(SVal X) { 1251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return isa<loc::ConcreteInt>(X); 126e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek} 127e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek 12899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 12999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// Error reporting. 13099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 13199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 132031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xubool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) { 1335f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const ObjCMessageExpr* ME = 1344ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 1351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1365f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const Expr * E = ME->getArg(Arg); 1371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 13823ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek if (isNil(N->getState()->getSVal(E))) { 139f1ae705460552655fe7275327804444c62e86baeTed Kremenek WarnNilArg(N, ME, Arg); 1404ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return true; 1414ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek } 1421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1434ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return false; 1444ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek} 1454ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek 14699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 14799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// NSString checking. 14899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 14999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 15014108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffbool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T, 151d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar llvm::StringRef ClassName) { 152d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar return ClassName == "NSString" || ClassName == "NSMutableString"; 15399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} 15499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 1551eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpbool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N, 1565f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const ObjCMessageExpr* ME) { 1571eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 15899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek Selector S = ME->getSelector(); 1591eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 16099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek if (S.isUnarySelector()) 16199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek return false; 16299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 16399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek // FIXME: This is going to be really slow doing these checks with 16499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek // lexical comparisons. 1651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 166077bf5e2f48acfa9e7d69429b6e4ba86ea14896dChris Lattner std::string name = S.getAsString(); 1679b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek assert (!name.empty()); 1689b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek const char* cstr = &name[0]; 1699b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek unsigned len = name.size(); 1701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1719b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek switch (len) { 1729b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek default: 1739b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek break; 1741eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump case 8: 1754ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "compare:")) 1764ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 1771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1784ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek break; 1791eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1808730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek case 15: 1818730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek // FIXME: Checking for initWithFormat: will not work in most cases 1828730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek // yet because [NSString alloc] returns id, not NSString*. We will 1838730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek // need support for tracking expected-type information in the analyzer 1848730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek // to find these errors. 1858730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek if (!strcmp(cstr, "initWithFormat:")) 1868730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek return CheckNilArg(N, 0); 1871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1888730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek break; 1891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1904ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 16: 1914ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "compare:options:")) 1924ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 1931eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1944ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek break; 1951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1964ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 22: 1974ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "compare:options:range:")) 1984ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 1991eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2004ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek break; 2011eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2024ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 23: 2031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2044ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "caseInsensitiveCompare:")) 2054ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 2061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2079b3fdeaca3660789d89e3980dc7d41e8676cd901Ted Kremenek break; 2088730e130ab77ae5739e6339e1544b4ca9ab28450Ted Kremenek 2094ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 29: 2104ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "compare:options:range:locale:")) 2114ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 2121eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2131eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump break; 2141eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2154ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek case 37: 2164ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek if (!strcmp(cstr, "componentsSeparatedByCharactersInSet:")) 2174ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return CheckNilArg(N, 0); 2181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump break; 22099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek } 2211eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 22299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek return false; 22399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} 22404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 22504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek//===----------------------------------------------------------------------===// 22604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek// Error reporting. 22704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek//===----------------------------------------------------------------------===// 22804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 22904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremeneknamespace { 23004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 231ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass AuditCFNumberCreate : public GRSimpleAPICheck { 232cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek APIMisuse* BT; 2331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 23404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: Either this should be refactored into GRSimpleAPICheck, or 23504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // it should always be passed with a call to Audit. The latter 23604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // approach makes this class more stateless. 23704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek ASTContext& Ctx; 23804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek IdentifierInfo* II; 239cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BugReporter& BR; 24023ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek 24104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekpublic: 2421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump AuditCFNumberCreate(ASTContext& ctx, BugReporter& br) 24323ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek : BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), BR(br){} 2441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 245cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek ~AuditCFNumberCreate() {} 2461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 247c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bool Audit(ExplodedNode* N, GRStateManager&); 2481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 24904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekprivate: 250c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu void AddError(const TypedRegion* R, const Expr* Ex, ExplodedNode *N, 2511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); 25204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}; 25304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} // end anonymous namespace 25404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 25504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekenum CFNumberType { 25604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt8Type = 1, 25704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt16Type = 2, 25804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt32Type = 3, 25904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt64Type = 4, 26004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberFloat32Type = 5, 26104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberFloat64Type = 6, 26204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberCharType = 7, 26304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberShortType = 8, 26404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberIntType = 9, 26504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberLongType = 10, 26604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberLongLongType = 11, 26704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberFloatType = 12, 26804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberDoubleType = 13, 26904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberCFIndexType = 14, 27004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberNSIntegerType = 15, 27104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberCGFloatType = 16 27204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}; 27304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 27404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremeneknamespace { 27504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek template<typename T> 27604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek class Optional { 27704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek bool IsKnown; 27804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek T Val; 27904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek public: 28004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek Optional() : IsKnown(false), Val(0) {} 28104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek Optional(const T& val) : IsKnown(true), Val(val) {} 2821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 28304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek bool isKnown() const { return IsKnown; } 28404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 28504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek const T& getValue() const { 28604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek assert (isKnown()); 28704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return Val; 28804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek } 28904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 29004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek operator const T&() const { 29104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return getValue(); 29204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek } 29304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek }; 29404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 29504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 29604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekstatic Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) { 2972550d70aabb5f603e8f74cc5fb6a69a7af5b51f3Nuno Lopes static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; 2981eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 29904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (i < kCFNumberCharType) 30004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return FixedSize[i-1]; 3011eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 30204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek QualType T; 3031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 30404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek switch (i) { 30504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberCharType: T = Ctx.CharTy; break; 30604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberShortType: T = Ctx.ShortTy; break; 30704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberIntType: T = Ctx.IntTy; break; 30804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberLongType: T = Ctx.LongTy; break; 30904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberLongLongType: T = Ctx.LongLongTy; break; 31004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberFloatType: T = Ctx.FloatTy; break; 31104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberDoubleType: T = Ctx.DoubleTy; break; 31204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberCFIndexType: 31304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberNSIntegerType: 31404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberCGFloatType: 3151eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // FIXME: We need a way to map from names to Type*. 31604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek default: 31704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return Optional<uint64_t>(); 31804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek } 3191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 32004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return Ctx.getTypeSize(T); 32104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 32204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 32304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek#if 0 32404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekstatic const char* GetCFNumberTypeStr(uint64_t i) { 32504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek static const char* Names[] = { 32604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt8Type", 32704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt16Type", 32804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt32Type", 32904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt64Type", 33004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberFloat32Type", 33104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberFloat64Type", 33204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberCharType", 33304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberShortType", 33404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberIntType", 33504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberLongType", 33604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberLongLongType", 33704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberFloatType", 33804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberDoubleType", 33904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberCFIndexType", 34004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberNSIntegerType", 34104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberCGFloatType" 34204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek }; 3431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 34404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType"; 34504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 34604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek#endif 34704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 3481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpbool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){ 3495f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const CallExpr* CE = 3505f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 3511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump const Expr* Callee = CE->getCallee(); 3521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump SVal CallV = N->getState()->getSVal(Callee); 353369f447eded97e6048ced02c0c2be3842f61fc1cZhongxing Xu const FunctionDecl* FD = CallV.getAsFunctionDecl(); 35404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 355369f447eded97e6048ced02c0c2be3842f61fc1cZhongxing Xu if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3) 35604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3571eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 35804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // Get the value of the "theType" argument. 35923ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek SVal TheTypeVal = N->getState()->getSVal(CE->getArg(1)); 3601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 36104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: We really should allow ranges of valid theType values, and 36204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // bifurcate the state appropriately. 3631c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xu nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal); 3641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 36504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (!V) 36604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 36804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t NumberKind = V->getValue().getLimitedValue(); 36904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind); 3701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 37104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: In some cases we can emit an error. 37204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (!TargetSize.isKnown()) 37304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3741eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 37504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // Look at the value of the integer being passed by reference. Essentially 37604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // we want to catch cases where the value passed in is not equal to the 37704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // size of the type being created. 37823ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek SVal TheValueExpr = N->getState()->getSVal(CE->getArg(2)); 3791eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 38004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: Eventually we should handle arbitrary locations. We can do this 38104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // by having an enhanced memory model that does low-level typing. 3821c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xu loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr); 38304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 38404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (!LV) 38504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 387479529e679957fbb92b56e116e3c86734429331eZhongxing Xu const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts()); 3885e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek 3895e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek if (!R) 3905e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek return false; 3915e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek 392a82d8aa5b3b3d24998b4d98b9f45a43cc84cac6fZhongxing Xu QualType T = Ctx.getCanonicalType(R->getValueType(Ctx)); 3931eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 39404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: If the pointee isn't an integer type, should we flag a warning? 39504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // People can do weird stuff with pointers. 3961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3971eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (!T->isIntegerType()) 39804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3991eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 40004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t SourceSize = Ctx.getTypeSize(T); 4011eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 40204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // CHECK: is SourceSize == TargetSize 4031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 40404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (SourceSize == TargetSize) 40504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 4061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 4079e24049bef26b6289cce9ac9b483c5cbb096e3aeTed Kremenek AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind); 4081eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 40904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: We can actually create an abstract "CFNumber" object that has 41004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // the bits initialized to the provided values. 41104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return SourceSize < TargetSize; 41204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 41304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 4145f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenekvoid AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex, 415c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu ExplodedNode *N, 41604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t SourceSize, uint64_t TargetSize, 41704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t NumberKind) { 4181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 419cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek std::string sbuf; 420cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek llvm::raw_string_ostream os(sbuf); 4211eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 42204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek os << (SourceSize == 8 ? "An " : "A ") 42304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek << SourceSize << " bit integer is used to initialize a CFNumber " 42404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "object that represents " 42504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek << (TargetSize == 8 ? "an " : "a ") 4261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump << TargetSize << " bit integer. "; 42704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 42804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (SourceSize < TargetSize) 42904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek os << (TargetSize - SourceSize) 4301eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump << " bits of the CFNumber value will be garbage." ; 43104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek else 43204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek os << (SourceSize - TargetSize) 43304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek << " bits of the input integer will be lost."; 4341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 435cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // Lazily create the BugType object. This will be owned 436cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // by the BugReporter object 'BR' once we call BR.EmitWarning. 437cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate"); 4384988a9a278c50fddf46d38331e4a136a91487b7dBenjamin Kramer RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); 439cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek report->addRange(Ex->getSourceRange()); 440cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BR.EmitReport(report); 44104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 44204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 44304bc87683acacce119967dfa5f7c35b4ecef012aTed KremenekGRSimpleAPICheck* 4441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpclang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) { 44523ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek return new AuditCFNumberCreate(Ctx, BR); 44604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 44704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 44878d46242e3351484c2b773f5610beba5d316914bTed Kremenek//===----------------------------------------------------------------------===// 44979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek// CFRetain/CFRelease auditing for null arguments. 45079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===// 45179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 45279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremeneknamespace { 453ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass AuditCFRetainRelease : public GRSimpleAPICheck { 45479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek APIMisuse *BT; 4551eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 45679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // FIXME: Either this should be refactored into GRSimpleAPICheck, or 45779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // it should always be passed with a call to Audit. The latter 45879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // approach makes this class more stateless. 45979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek ASTContext& Ctx; 46079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek IdentifierInfo *Retain, *Release; 46179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BugReporter& BR; 4621eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 46379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenekpublic: 4641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump AuditCFRetainRelease(ASTContext& ctx, BugReporter& br) 46579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek : BT(0), Ctx(ctx), 46679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek Retain(&Ctx.Idents.get("CFRetain")), Release(&Ctx.Idents.get("CFRelease")), 46779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BR(br){} 4681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 46979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek ~AuditCFRetainRelease() {} 4701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 471c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bool Audit(ExplodedNode* N, GRStateManager&); 47279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek}; 47379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} // end anonymous namespace 47479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 47579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 476c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xubool AuditCFRetainRelease::Audit(ExplodedNode* N, GRStateManager&) { 4775f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 4781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 47979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // If the CallExpr doesn't have exactly 1 argument just give up checking. 48079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (CE->getNumArgs() != 1) 48179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 4821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 48379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // Check if we called CFRetain/CFRelease. 48479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek const GRState* state = N->getState(); 48579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek SVal X = state->getSVal(CE->getCallee()); 48679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek const FunctionDecl* FD = X.getAsFunctionDecl(); 4871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 48879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (!FD) 48979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 4901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 4911eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump const IdentifierInfo *FuncII = FD->getIdentifier(); 49279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (!(FuncII == Retain || FuncII == Release)) 49379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 4941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 49579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // Finally, check if the argument is NULL. 49679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // FIXME: We should be able to bifurcate the state here, as a successful 49779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // check will result in the value not being NULL afterwards. 49879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // FIXME: Need a way to register vistors for the BugReporter. Would like 49979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // to benefit from the same diagnostics that regular null dereference 50079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // reporting has. 50179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (state->getStateManager().isEqual(state, CE->getArg(0), 0)) { 50279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (!BT) 50379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BT = new APIMisuse("null passed to CFRetain/CFRelease"); 5041eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 50579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek const char *description = (FuncII == Retain) 50679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek ? "Null pointer argument in call to CFRetain" 50779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek : "Null pointer argument in call to CFRelease"; 50879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 50979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek RangedBugReport *report = new RangedBugReport(*BT, description, N); 51079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek report->addRange(CE->getArg(0)->getSourceRange()); 51179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BR.EmitReport(report); 51279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return true; 51379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek } 51479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 51579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 51679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} 5171eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 51979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted KremenekGRSimpleAPICheck* 5201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpclang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) { 52179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return new AuditCFRetainRelease(Ctx, BR); 52279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} 52379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 52479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===// 52550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek// Check for sending 'retain', 'release', or 'autorelease' directly to a Class. 52650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek//===----------------------------------------------------------------------===// 52750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 52850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremeneknamespace { 529ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass ClassReleaseChecker : 53050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek public CheckerVisitor<ClassReleaseChecker> { 53150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector releaseS; 53250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector retainS; 53350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector autoreleaseS; 53450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector drainS; 53550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek BugType *BT; 53650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenekpublic: 53750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek ClassReleaseChecker(ASTContext &Ctx) 53850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek : releaseS(GetNullarySelector("release", Ctx)), 53950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek retainS(GetNullarySelector("retain", Ctx)), 54050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek autoreleaseS(GetNullarySelector("autorelease", Ctx)), 54150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek drainS(GetNullarySelector("drain", Ctx)), 54250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek BT(0) {} 54350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 54450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek static void *getTag() { static int x = 0; return &x; } 54550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 54650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); 54750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek}; 54850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek} 54950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 55050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenekvoid ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, 55150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek const ObjCMessageExpr *ME) { 55250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 55350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek const IdentifierInfo *ClsName = ME->getClassName(); 55450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek if (!ClsName) 55550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek return; 55650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 55750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector S = ME->getSelector(); 558921ddc4e7ef35d77965205d91582c356cb54f5efBenjamin Kramer if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) 55950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek return; 56050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 56150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek if (!BT) 56250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek BT = new APIMisuse("message incorrectly sent to class instead of class " 56350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek "instance"); 56450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 56519d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek ExplodedNode *N = C.GenerateNode(); 56619d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek 56750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek if (!N) 56850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek return; 56950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 57050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek llvm::SmallString<200> buf; 57150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek llvm::raw_svector_ostream os(buf); 57250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 57350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek os << "The '" << S.getAsString() << "' message should be sent to instances " 57450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek "of class '" << ClsName->getName() 57550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek << "' and not the class directly"; 57650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 57750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); 57850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek report->addRange(ME->getSourceRange()); 57950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek C.EmitReport(report); 58050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek} 58150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 58250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek//===----------------------------------------------------------------------===// 58378d46242e3351484c2b773f5610beba5d316914bTed Kremenek// Check registration. 58479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===// 58578d46242e3351484c2b773f5610beba5d316914bTed Kremenek 5865ab128b02d3b10413fb30738ec9f401dcfb47252Zhongxing Xuvoid clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) { 58778d46242e3351484c2b773f5610beba5d316914bTed Kremenek ASTContext& Ctx = Eng.getContext(); 588cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BugReporter &BR = Eng.getBugReporter(); 58978d46242e3351484c2b773f5610beba5d316914bTed Kremenek 59023ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, BR), 59178d46242e3351484c2b773f5610beba5d316914bTed Kremenek Stmt::ObjCMessageExprClass); 5921eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR), Stmt::CallExprClass); 59379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass); 5941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5955ab128b02d3b10413fb30738ec9f401dcfb47252Zhongxing Xu RegisterNSErrorChecks(BR, Eng, D); 59654cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek RegisterNSAutoreleasePoolChecks(Eng); 59750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Eng.registerCheck(new ClassReleaseChecker(Ctx)); 59878d46242e3351484c2b773f5610beba5d316914bTed Kremenek} 599