BasicObjCFoundationChecks.cpp revision 04badcf84c8d504d8491c7c7e29b58f52cb16640
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 181309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/ExplodedGraph.h" 191309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h" 201309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/GRExprEngine.h" 211309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/GRState.h" 225e2d2c2ee3cf410643e0f9a5701708e51409d973Benjamin Kramer#include "clang/Checker/BugReporter/BugType.h" 231309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/MemRegion.h" 241309f9a3b225ea846e5822691c39a77423125505Ted Kremenek#include "clang/Checker/PathSensitive/CheckerVisitor.h" 2597053091c0e4df12ffb662b284b6ab329ca1c40fTed Kremenek#include "clang/Checker/Checkers/LocalCheckers.h" 26c4a1dea2dc56bd1357ec91b829a0b9e68229a13eDaniel Dunbar#include "clang/AST/DeclObjC.h" 2799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "clang/AST/Expr.h" 28f494b579b22f9950f5af021f0bf9879a91bb8b41Steve Naroff#include "clang/AST/ExprObjC.h" 2999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek#include "clang/AST/ASTContext.h" 3099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 3199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekusing namespace clang; 32f1ae705460552655fe7275327804444c62e86baeTed Kremenek 3314108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffstatic const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { 3404badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor QualType T; 3504badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor switch (ME->getReceiverKind()) { 3604badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor case ObjCMessageExpr::Instance: 3704badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor T = ME->getInstanceReceiver()->getType(); 3804badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor break; 3904badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor 4004badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor case ObjCMessageExpr::SuperInstance: 4104badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor T = ME->getSuperType(); 4204badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor break; 4304badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor 4404badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor case ObjCMessageExpr::Class: 4504badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor case ObjCMessageExpr::SuperClass: 4604badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor return 0; 4704badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor } 481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 4904badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>()) 5014108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff return PT->getInterfaceType(); 51c1ff3cd5fe4436bb14309fdc5ee7e1c2b702b7c3Ted Kremenek 52c1ff3cd5fe4436bb14309fdc5ee7e1c2b702b7c3Ted Kremenek return NULL; 53f1ae705460552655fe7275327804444c62e86baeTed Kremenek} 54f1ae705460552655fe7275327804444c62e86baeTed Kremenek 5514108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffstatic const char* GetReceiverNameType(const ObjCMessageExpr* ME) { 56e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME)) 57e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar return ReceiverType->getDecl()->getIdentifier()->getNameStart(); 58e013d685c6689ac7ae103ee88acf573422d1ed6aDaniel Dunbar return NULL; 59f1ae705460552655fe7275327804444c62e86baeTed Kremenek} 60f1ae705460552655fe7275327804444c62e86baeTed Kremenek 6199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremeneknamespace { 62b344f91f00021b88e365a4a38502090c3b0cef12Ted Kremenek 63ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass APIMisuse : public BugType { 64f1ae705460552655fe7275327804444c62e86baeTed Kremenekpublic: 65cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {} 66f1ae705460552655fe7275327804444c62e86baeTed Kremenek}; 671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 68ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass BasicObjCFoundationChecks : public GRSimpleAPICheck { 69cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek APIMisuse *BT; 70cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BugReporter& BR; 71e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek ASTContext &Ctx; 721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 73d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar bool isNSString(const ObjCInterfaceType *T, llvm::StringRef suffix); 74031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME); 751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 761eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump void Warn(ExplodedNode* N, const Expr* E, const std::string& s); 77031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu void WarnNilArg(ExplodedNode* N, const Expr* E); 781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 79031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xu bool CheckNilArg(ExplodedNode* N, unsigned Arg); 8099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 8199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenekpublic: 821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump BasicObjCFoundationChecks(ASTContext& ctx, BugReporter& br) 8323ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek : BT(0), BR(br), Ctx(ctx) {} 841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 85c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bool Audit(ExplodedNode* N, GRStateManager&); 861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpprivate: 881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump void WarnNilArg(ExplodedNode* N, const ObjCMessageExpr* ME, unsigned Arg) { 89cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek std::string sbuf; 90cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek llvm::raw_string_ostream os(sbuf); 91cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek os << "Argument to '" << GetReceiverNameType(ME) << "' method '" 92cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek << ME->getSelector().getAsString() << "' cannot be nil."; 931eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 94cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // Lazily create the BugType object for NilArg. This will be owned 95cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // by the BugReporter object 'BR' once we call BR.EmitWarning. 96cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek if (!BT) BT = new APIMisuse("nil argument"); 971eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 984988a9a278c50fddf46d38331e4a136a91487b7dBenjamin Kramer RangedBugReport *R = new RangedBugReport(*BT, os.str(), N); 99cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek R->addRange(ME->getArg(Arg)->getSourceRange()); 100cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BR.EmitReport(R); 101f1ae705460552655fe7275327804444c62e86baeTed Kremenek } 10299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek}; 1031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 10499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} // end anonymous namespace 10599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 10699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 107527556184b276c545be1355ad596fce29a0400fbTed KremenekGRSimpleAPICheck* 10823ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenekclang::CreateBasicObjCFoundationChecks(ASTContext& Ctx, BugReporter& BR) { 1091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return new BasicObjCFoundationChecks(Ctx, BR); 110527556184b276c545be1355ad596fce29a0400fbTed Kremenek} 111527556184b276c545be1355ad596fce29a0400fbTed Kremenek 1124ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek 11399c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 114c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xubool BasicObjCFoundationChecks::Audit(ExplodedNode* N, 1154adc81e540b874bafa15715fd2c5cb662463debdTed Kremenek GRStateManager&) { 1161eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1175f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const ObjCMessageExpr* ME = 1184ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 1194ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek 12014108da7f7fc059772711e4ffee1322a27b152a7Steve Naroff const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); 1211eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 12299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek if (!ReceiverType) 123f74279447d4ad0a0c0f2e6e6740d5a0f4c242e0cNuno Lopes return false; 1241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 125d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar if (isNSString(ReceiverType, 12601eb9b9683535d8a65c704ad2c545903409e2d36Daniel Dunbar ReceiverType->getDecl()->getIdentifier()->getName())) 12799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek return AuditNSString(N, ME); 12899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 129f74279447d4ad0a0c0f2e6e6740d5a0f4c242e0cNuno Lopes return false; 13099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} 13199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 1321c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xustatic inline bool isNil(SVal X) { 1331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return isa<loc::ConcreteInt>(X); 134e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek} 135e5d5c204c761cc3b2a6374a15b035420f207c7afTed Kremenek 13699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 13799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// Error reporting. 13899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 13999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 140031ccc0555a82afc2e8afe29e19dd57ff204e2deZhongxing Xubool BasicObjCFoundationChecks::CheckNilArg(ExplodedNode* N, unsigned Arg) { 1415f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const ObjCMessageExpr* ME = 1424ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 1431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1445f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const Expr * E = ME->getArg(Arg); 1451eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1461397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek if (isNil(N->getState()->getSVal(E))) { 147f1ae705460552655fe7275327804444c62e86baeTed Kremenek WarnNilArg(N, ME, Arg); 1484ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return true; 1494ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek } 1501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1514ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek return false; 1524ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek} 1534ba6283f9c7db4513ca2d9cbde7df3a58ba941f7Ted Kremenek 15499c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 15599c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek// NSString checking. 15699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek//===----------------------------------------------------------------------===// 15799c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 15814108da7f7fc059772711e4ffee1322a27b152a7Steve Naroffbool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T, 159d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar llvm::StringRef ClassName) { 160d777d58714fc26c645e061ed7aa43ecb05ab41a8Daniel Dunbar return ClassName == "NSString" || ClassName == "NSMutableString"; 16199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} 16299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 1631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpbool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N, 1645f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const ObjCMessageExpr* ME) { 1651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 16699c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek Selector S = ME->getSelector(); 1671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 16899c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek if (S.isUnarySelector()) 16999c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek return false; 17099c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek 17199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek // FIXME: This is going to be really slow doing these checks with 17299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek // lexical comparisons. 1731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 174064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer std::string NameStr = S.getAsString(); 175064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer llvm::StringRef Name(NameStr); 176064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer assert(!Name.empty()); 177064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer 178064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer // FIXME: Checking for initWithFormat: will not work in most cases 179064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer // yet because [NSString alloc] returns id, not NSString*. We will 180064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer // need support for tracking expected-type information in the analyzer 181064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer // to find these errors. 182064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer if (Name == "caseInsensitiveCompare:" || 183064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer Name == "compare:" || 184064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer Name == "compare:options:" || 185064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer Name == "compare:options:range:" || 186064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer Name == "compare:options:range:locale:" || 187064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer Name == "componentsSeparatedByCharactersInSet:" || 188064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer Name == "initWithFormat:") 189064fb20e7a29d00f29bf10f9d7f54d36456a2449Benjamin Kramer return CheckNilArg(N, 0); 1901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 19199c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek return false; 19299c6ad3f22b865d0f4cce52bc36904403c9ed4c4Ted Kremenek} 19304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 19404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek//===----------------------------------------------------------------------===// 19504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek// Error reporting. 19604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek//===----------------------------------------------------------------------===// 19704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 19804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremeneknamespace { 19904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 200ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass AuditCFNumberCreate : public GRSimpleAPICheck { 201cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek APIMisuse* BT; 2021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 20304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: Either this should be refactored into GRSimpleAPICheck, or 20404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // it should always be passed with a call to Audit. The latter 20504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // approach makes this class more stateless. 20604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek ASTContext& Ctx; 20704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek IdentifierInfo* II; 208cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BugReporter& BR; 20923ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek 21004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekpublic: 2111eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump AuditCFNumberCreate(ASTContext& ctx, BugReporter& br) 21223ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek : BT(0), Ctx(ctx), II(&Ctx.Idents.get("CFNumberCreate")), BR(br){} 2131eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 214cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek ~AuditCFNumberCreate() {} 2151eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 216c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bool Audit(ExplodedNode* N, GRStateManager&); 2171eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 21804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekprivate: 219c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu void AddError(const TypedRegion* R, const Expr* Ex, ExplodedNode *N, 2201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); 22104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}; 22204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} // end anonymous namespace 22304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 22404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekenum CFNumberType { 22504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt8Type = 1, 22604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt16Type = 2, 22704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt32Type = 3, 22804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberSInt64Type = 4, 22904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberFloat32Type = 5, 23004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberFloat64Type = 6, 23104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberCharType = 7, 23204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberShortType = 8, 23304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberIntType = 9, 23404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberLongType = 10, 23504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberLongLongType = 11, 23604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberFloatType = 12, 23704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberDoubleType = 13, 23804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberCFIndexType = 14, 23904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberNSIntegerType = 15, 24004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek kCFNumberCGFloatType = 16 24104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek}; 24204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 24304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremeneknamespace { 24404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek template<typename T> 24504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek class Optional { 24604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek bool IsKnown; 24704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek T Val; 24804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek public: 24904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek Optional() : IsKnown(false), Val(0) {} 25004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek Optional(const T& val) : IsKnown(true), Val(val) {} 2511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 25204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek bool isKnown() const { return IsKnown; } 25304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 25404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek const T& getValue() const { 25504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek assert (isKnown()); 25604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return Val; 25704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek } 25804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 25904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek operator const T&() const { 26004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return getValue(); 26104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek } 26204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek }; 26304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 26404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 26504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekstatic Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) { 2662550d70aabb5f603e8f74cc5fb6a69a7af5b51f3Nuno Lopes static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; 2671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 26804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (i < kCFNumberCharType) 26904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return FixedSize[i-1]; 2701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 27104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek QualType T; 2721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 27304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek switch (i) { 27404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberCharType: T = Ctx.CharTy; break; 27504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberShortType: T = Ctx.ShortTy; break; 27604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberIntType: T = Ctx.IntTy; break; 27704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberLongType: T = Ctx.LongTy; break; 27804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberLongLongType: T = Ctx.LongLongTy; break; 27904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberFloatType: T = Ctx.FloatTy; break; 28004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberDoubleType: T = Ctx.DoubleTy; break; 28104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberCFIndexType: 28204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberNSIntegerType: 28304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek case kCFNumberCGFloatType: 2841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // FIXME: We need a way to map from names to Type*. 28504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek default: 28604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return Optional<uint64_t>(); 28704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek } 2881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 28904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return Ctx.getTypeSize(T); 29004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 29104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 29204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek#if 0 29304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenekstatic const char* GetCFNumberTypeStr(uint64_t i) { 29404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek static const char* Names[] = { 29504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt8Type", 29604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt16Type", 29704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt32Type", 29804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberSInt64Type", 29904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberFloat32Type", 30004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberFloat64Type", 30104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberCharType", 30204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberShortType", 30304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberIntType", 30404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberLongType", 30504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberLongLongType", 30604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberFloatType", 30704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberDoubleType", 30804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberCFIndexType", 30904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberNSIntegerType", 31004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "kCFNumberCGFloatType" 31104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek }; 3121eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 31304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType"; 31404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 31504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek#endif 31604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 3171eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpbool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){ 3185f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const CallExpr* CE = 3195f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 3201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump const Expr* Callee = CE->getCallee(); 3211397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek SVal CallV = N->getState()->getSVal(Callee); 322369f447eded97e6048ced02c0c2be3842f61fc1cZhongxing Xu const FunctionDecl* FD = CallV.getAsFunctionDecl(); 32304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 324369f447eded97e6048ced02c0c2be3842f61fc1cZhongxing Xu if (!FD || FD->getIdentifier() != II || CE->getNumArgs()!=3) 32504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 32704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // Get the value of the "theType" argument. 3281397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek SVal TheTypeVal = N->getState()->getSVal(CE->getArg(1)); 3291eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 33004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: We really should allow ranges of valid theType values, and 33104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // bifurcate the state appropriately. 3321c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xu nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal); 3331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 33404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (!V) 33504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 33704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t NumberKind = V->getValue().getLimitedValue(); 33804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind); 3391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 34004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: In some cases we can emit an error. 34104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (!TargetSize.isKnown()) 34204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 34404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // Look at the value of the integer being passed by reference. Essentially 34504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // we want to catch cases where the value passed in is not equal to the 34604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // size of the type being created. 3471397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek SVal TheValueExpr = N->getState()->getSVal(CE->getArg(2)); 3481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 34904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: Eventually we should handle arbitrary locations. We can do this 35004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // by having an enhanced memory model that does low-level typing. 3511c96b24285d05c0eac455ae96d7c9ff43d42bc96Zhongxing Xu loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr); 35204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 35304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (!LV) 35404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3551eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 356479529e679957fbb92b56e116e3c86734429331eZhongxing Xu const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts()); 3575e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek 3585e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek if (!R) 3595e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek return false; 3605e77ebae47099d76020e84e604b33bb33c9006c3Ted Kremenek 361a82d8aa5b3b3d24998b4d98b9f45a43cc84cac6fZhongxing Xu QualType T = Ctx.getCanonicalType(R->getValueType(Ctx)); 3621eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 36304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: If the pointee isn't an integer type, should we flag a warning? 36404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // People can do weird stuff with pointers. 3651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (!T->isIntegerType()) 36704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 36904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t SourceSize = Ctx.getTypeSize(T); 3701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 37104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // CHECK: is SourceSize == TargetSize 3721eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 37304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (SourceSize == TargetSize) 37404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return false; 3751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3769e24049bef26b6289cce9ac9b483c5cbb096e3aeTed Kremenek AddError(R, CE->getArg(2), N, SourceSize, TargetSize, NumberKind); 3771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 37804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // FIXME: We can actually create an abstract "CFNumber" object that has 37904bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek // the bits initialized to the provided values. 38004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek return SourceSize < TargetSize; 38104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 38204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 3835f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenekvoid AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex, 384c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu ExplodedNode *N, 38504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t SourceSize, uint64_t TargetSize, 38604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek uint64_t NumberKind) { 3871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 388cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek std::string sbuf; 389cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek llvm::raw_string_ostream os(sbuf); 3901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 39104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek os << (SourceSize == 8 ? "An " : "A ") 39204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek << SourceSize << " bit integer is used to initialize a CFNumber " 39304bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek "object that represents " 39404bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek << (TargetSize == 8 ? "an " : "a ") 3951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump << TargetSize << " bit integer. "; 39604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 39704bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek if (SourceSize < TargetSize) 39804bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek os << (TargetSize - SourceSize) 3991eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump << " bits of the CFNumber value will be garbage." ; 40004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek else 40104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek os << (SourceSize - TargetSize) 40204bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek << " bits of the input integer will be lost."; 4031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 404cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // Lazily create the BugType object. This will be owned 405cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek // by the BugReporter object 'BR' once we call BR.EmitWarning. 406cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate"); 4074988a9a278c50fddf46d38331e4a136a91487b7dBenjamin Kramer RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); 408cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek report->addRange(Ex->getSourceRange()); 409cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BR.EmitReport(report); 41004bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 41104bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 41204bc87683acacce119967dfa5f7c35b4ecef012aTed KremenekGRSimpleAPICheck* 4131eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpclang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) { 41423ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek return new AuditCFNumberCreate(Ctx, BR); 41504bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek} 41604bc87683acacce119967dfa5f7c35b4ecef012aTed Kremenek 41778d46242e3351484c2b773f5610beba5d316914bTed Kremenek//===----------------------------------------------------------------------===// 41879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek// CFRetain/CFRelease auditing for null arguments. 41979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===// 42079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 42179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremeneknamespace { 422ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass AuditCFRetainRelease : public GRSimpleAPICheck { 42379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek APIMisuse *BT; 4241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 42579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // FIXME: Either this should be refactored into GRSimpleAPICheck, or 42679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // it should always be passed with a call to Audit. The latter 42779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // approach makes this class more stateless. 42879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek ASTContext& Ctx; 42979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek IdentifierInfo *Retain, *Release; 43079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BugReporter& BR; 4311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 43279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenekpublic: 4331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump AuditCFRetainRelease(ASTContext& ctx, BugReporter& br) 43479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek : BT(0), Ctx(ctx), 43579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek Retain(&Ctx.Idents.get("CFRetain")), Release(&Ctx.Idents.get("CFRelease")), 43679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BR(br){} 4371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 43879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek ~AuditCFRetainRelease() {} 4391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 440c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xu bool Audit(ExplodedNode* N, GRStateManager&); 44179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek}; 44279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} // end anonymous namespace 44379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 44479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 445c5619d901a68dc27a9e310a6a831f03efebcd950Zhongxing Xubool AuditCFRetainRelease::Audit(ExplodedNode* N, GRStateManager&) { 4465f85e17df3f5b0a8021443f2b590daecfb2cbd17Ted Kremenek const CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt()); 4471eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 44879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // If the CallExpr doesn't have exactly 1 argument just give up checking. 44979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (CE->getNumArgs() != 1) 45079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 4511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 45279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // Check if we called CFRetain/CFRelease. 45379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek const GRState* state = N->getState(); 4541397663af9dbcc24dbf0e11de43931b3dc08fdbbTed Kremenek SVal X = state->getSVal(CE->getCallee()); 45579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek const FunctionDecl* FD = X.getAsFunctionDecl(); 4561eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 45779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (!FD) 45879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 4591eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 4601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump const IdentifierInfo *FuncII = FD->getIdentifier(); 46179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (!(FuncII == Retain || FuncII == Release)) 46279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 4631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 46479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // Finally, check if the argument is NULL. 46579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // FIXME: We should be able to bifurcate the state here, as a successful 46679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // check will result in the value not being NULL afterwards. 46779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // FIXME: Need a way to register vistors for the BugReporter. Would like 46879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // to benefit from the same diagnostics that regular null dereference 46979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek // reporting has. 47079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (state->getStateManager().isEqual(state, CE->getArg(0), 0)) { 47179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek if (!BT) 47279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BT = new APIMisuse("null passed to CFRetain/CFRelease"); 4731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 47479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek const char *description = (FuncII == Retain) 47579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek ? "Null pointer argument in call to CFRetain" 47679b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek : "Null pointer argument in call to CFRelease"; 47779b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 47879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek RangedBugReport *report = new RangedBugReport(*BT, description, N); 47979b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek report->addRange(CE->getArg(0)->getSourceRange()); 48079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek BR.EmitReport(report); 48179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return true; 48279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek } 48379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 48479b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return false; 48579b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} 4861eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 4871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 48879b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted KremenekGRSimpleAPICheck* 4891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpclang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) { 49079b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek return new AuditCFRetainRelease(Ctx, BR); 49179b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek} 49279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek 49379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===// 49450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek// Check for sending 'retain', 'release', or 'autorelease' directly to a Class. 49550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek//===----------------------------------------------------------------------===// 49650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 49750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremeneknamespace { 498ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass ClassReleaseChecker : 49950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek public CheckerVisitor<ClassReleaseChecker> { 50050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector releaseS; 50150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector retainS; 50250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector autoreleaseS; 50350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector drainS; 50450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek BugType *BT; 50550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenekpublic: 50650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek ClassReleaseChecker(ASTContext &Ctx) 50750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek : releaseS(GetNullarySelector("release", Ctx)), 50850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek retainS(GetNullarySelector("retain", Ctx)), 50950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek autoreleaseS(GetNullarySelector("autorelease", Ctx)), 51050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek drainS(GetNullarySelector("drain", Ctx)), 51150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek BT(0) {} 51250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 51350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek static void *getTag() { static int x = 0; return &x; } 51450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 51550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); 51650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek}; 51750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek} 51850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 51950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenekvoid ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, 52050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek const ObjCMessageExpr *ME) { 52104badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor ObjCInterfaceDecl *Class = 0; 52204badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor switch (ME->getReceiverKind()) { 52304badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor case ObjCMessageExpr::Class: 52404badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); 52504badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor break; 52604badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor 52704badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor case ObjCMessageExpr::SuperClass: 52804badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); 52904badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor break; 53004badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor 53104badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor case ObjCMessageExpr::Instance: 53204badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor case ObjCMessageExpr::SuperInstance: 53350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek return; 53404badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor } 53504badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor 53650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Selector S = ME->getSelector(); 537921ddc4e7ef35d77965205d91582c356cb54f5efBenjamin Kramer if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) 53850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek return; 53950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 54050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek if (!BT) 54150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek BT = new APIMisuse("message incorrectly sent to class instead of class " 54250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek "instance"); 54350e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 54419d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek ExplodedNode *N = C.GenerateNode(); 54519d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek 54650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek if (!N) 54750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek return; 54850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 54950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek llvm::SmallString<200> buf; 55050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek llvm::raw_svector_ostream os(buf); 55150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 55250e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek os << "The '" << S.getAsString() << "' message should be sent to instances " 55304badcf84c8d504d8491c7c7e29b58f52cb16640Douglas Gregor "of class '" << Class->getName() 55450e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek << "' and not the class directly"; 55550e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 55650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); 55750e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek report->addRange(ME->getSourceRange()); 55850e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek C.EmitReport(report); 55950e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek} 56050e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek 56150e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek//===----------------------------------------------------------------------===// 56278d46242e3351484c2b773f5610beba5d316914bTed Kremenek// Check registration. 56379b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek//===----------------------------------------------------------------------===// 56478d46242e3351484c2b773f5610beba5d316914bTed Kremenek 5655ab128b02d3b10413fb30738ec9f401dcfb47252Zhongxing Xuvoid clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) { 56678d46242e3351484c2b773f5610beba5d316914bTed Kremenek ASTContext& Ctx = Eng.getContext(); 567cf118d41f7930a18dce97416ef7834a62642f587Ted Kremenek BugReporter &BR = Eng.getBugReporter(); 56878d46242e3351484c2b773f5610beba5d316914bTed Kremenek 56923ec48cd3369c8d7d1ab3c3f2226cfcffd2cd3d3Ted Kremenek Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, BR), 57078d46242e3351484c2b773f5610beba5d316914bTed Kremenek Stmt::ObjCMessageExprClass); 5711eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, BR), Stmt::CallExprClass); 57279b4f7d37530a1c41df26b6ac3a159f7cd6388d6Ted Kremenek Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass); 5731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5745ab128b02d3b10413fb30738ec9f401dcfb47252Zhongxing Xu RegisterNSErrorChecks(BR, Eng, D); 57554cb7ccc769a5e81a13812e08c21daf52a781262Ted Kremenek RegisterNSAutoreleasePoolChecks(Eng); 57650e837b3cbc9315b6808daabb96c5c7cccf11ea7Ted Kremenek Eng.registerCheck(new ClassReleaseChecker(Ctx)); 57778d46242e3351484c2b773f5610beba5d316914bTed Kremenek} 578