1db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek//==- CheckObjCDealloc.cpp - Check ObjC -dealloc implementation --*- C++ -*-==// 2db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek// 3db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek// The LLVM Compiler Infrastructure 4db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek// 5db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek// This file is distributed under the University of Illinois Open Source 6db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek// License. See LICENSE.TXT for details. 7db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek// 8db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek//===----------------------------------------------------------------------===// 9db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek// 104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// This checker analyzes Objective-C -dealloc methods and their callees 114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// to warn about improper releasing of instance variables that back synthesized 124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// properties. It warns about missing releases in the following cases: 134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// - When a class has a synthesized instance variable for a 'retain' or 'copy' 144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// property and lacks a -dealloc method in its implementation. 154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// - When a class has a synthesized instance variable for a 'retain'/'copy' 164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// property but the ivar is not released in -dealloc by either -release 174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// or by nilling out the property. 184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// 194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// It warns about extra releases in -dealloc (but not in callees) when a 204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// synthesized instance variable is released in the following cases: 214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// - When the property is 'assign' and is not 'readonly'. 224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// - When the property is 'weak'. 234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// 244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// This checker only warns for instance variables synthesized to back 254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// properties. Handling the more general case would require inferring whether 264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// an instance variable is stored retained or not. For synthesized properties, 274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar// this is specified in the property declaration itself. 28db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek// 29db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek//===----------------------------------------------------------------------===// 30db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek 317dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis#include "ClangSACheckers.h" 322fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer#include "clang/AST/Attr.h" 33db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek#include "clang/AST/DeclObjC.h" 342fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer#include "clang/AST/Expr.h" 352fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer#include "clang/AST/ExprObjC.h" 363cd483cbbf8921f463b3ee91d5da8a63db9d1299Ted Kremenek#include "clang/Basic/LangOptions.h" 3755fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 3955fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 4055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/Checker.h" 4155fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 476f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek#include "llvm/Support/raw_ostream.h" 48db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek 49db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenekusing namespace clang; 509ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 51db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek 524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Indicates whether an instance variable is required to be released in 534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// -dealloc. 544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarenum class ReleaseRequirement { 554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar /// The instance variable must be released, either by calling 564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar /// -release on it directly or by nilling it out with a property setter. 574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar MustRelease, 586f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek 594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar /// The instance variable must not be directly released with -release. 604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar MustNotReleaseDirectly, 614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar /// The requirement for the instance variable could not be determined. 634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar Unknown 644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar}; 654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns true if the property implementation is synthesized and the 674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// type of the property is retainable. 684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarstatic bool isSynthesizedRetainableProperty(const ObjCPropertyImplDecl *I, 694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCIvarDecl **ID, 704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyDecl **PD) { 714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize) 734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar (*ID) = I->getPropertyIvarDecl(); 764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!(*ID)) 774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar QualType T = (*ID)->getType(); 804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!T->isObjCRetainableType()) 814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar (*PD) = I->getPropertyDecl(); 844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Shouldn't be able to synthesize a property that doesn't exist. 854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(*PD); 864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return true; 886f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek} 896f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek 904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarnamespace { 91db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek 924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarclass ObjCDeallocChecker 934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar : public Checker<check::ASTDecl<ObjCImplementationDecl>, 944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar check::PreObjCMessage, check::PostObjCMessage, 954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar check::PreCall, 964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar check::BeginFunction, check::EndFunction, 974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar eval::Assume, 984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar check::PointerEscape, 994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar check::PreStmt<ReturnStmt>> { 1001eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar mutable IdentifierInfo *NSObjectII, *SenTestCaseII, *XCTestCaseII, 1024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar *Block_releaseII, *CIFilterII; 1031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar mutable Selector DeallocSel, ReleaseSel; 1051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::unique_ptr<BugType> MissingReleaseBugType; 1074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::unique_ptr<BugType> ExtraReleaseBugType; 1084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::unique_ptr<BugType> MistakenDeallocBugType; 1091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarpublic: 1114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ObjCDeallocChecker(); 1121eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr, 1144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar BugReporter &BR) const; 1154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void checkBeginFunction(CheckerContext &Ctx) const; 1164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 1174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 1184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 1191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond, 1214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool Assumption) const; 1221eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef checkPointerEscape(ProgramStateRef State, 1244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const InvalidatedSymbols &Escaped, 1254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const CallEvent *Call, 1264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar PointerEscapeKind Kind) const; 1274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; 1284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void checkEndFunction(CheckerContext &Ctx) const; 1291eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarprivate: 1314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void diagnoseMissingReleases(CheckerContext &C) const; 1328cb6fb3bd80d0b051f37c31d8658666361b5b7bbTed Kremenek 1334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool diagnoseExtraRelease(SymbolRef ReleasedValue, const ObjCMethodCall &M, 1344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const; 1351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool diagnoseMistakenDealloc(SymbolRef DeallocedValue, 1374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCMethodCall &M, 1384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const; 1398cb6fb3bd80d0b051f37c31d8658666361b5b7bbTed Kremenek 1404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef getValueReleasedByNillingOut(const ObjCMethodCall &M, 1414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const; 1428cb6fb3bd80d0b051f37c31d8658666361b5b7bbTed Kremenek 1434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCIvarRegion *getIvarRegionForIvarSymbol(SymbolRef IvarSym) const; 1444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef getInstanceSymbolFromIvarSymbol(SymbolRef IvarSym) const; 1454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyImplDecl* 1474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar findPropertyOnDeallocatingInstance(SymbolRef IvarSym, 1484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const; 1494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ReleaseRequirement 1514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar getDeallocReleaseRequirement(const ObjCPropertyImplDecl *PropImpl) const; 1524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool isInInstanceDealloc(const CheckerContext &C, SVal &SelfValOut) const; 1544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool isInInstanceDealloc(const CheckerContext &C, const LocationContext *LCtx, 1554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal &SelfValOut) const; 1564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool instanceDeallocIsOnStack(const CheckerContext &C, 1574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal &InstanceValOut) const; 1584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool isSuperDeallocMessage(const ObjCMethodCall &M) const; 1604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCImplDecl *getContainingObjCImpl(const LocationContext *LCtx) const; 1624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyDecl * 1644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar findShadowedPropertyDecl(const ObjCPropertyImplDecl *PropImpl) const; 1654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void transitionToReleaseValue(CheckerContext &C, SymbolRef Value) const; 1674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef removeValueRequiringRelease(ProgramStateRef State, 1684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef InstanceSym, 1694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef ValueSym) const; 1704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar void initIdentifierInfoAndSelectors(ASTContext &Ctx) const; 1724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool classHasSeparateTeardown(const ObjCInterfaceDecl *ID) const; 1744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool isReleasedByCIFilterDealloc(const ObjCPropertyImplDecl *PropImpl) const; 1764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar}; 1774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} // End anonymous namespace. 1784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainartypedef llvm::ImmutableSet<SymbolRef> SymbolSet; 1804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Maps from the symbol for a class instance to the set of 1824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// symbols remaining that must be released in -dealloc. 1834967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarREGISTER_MAP_WITH_PROGRAMSTATE(UnreleasedIvarMap, SymbolRef, SymbolSet) 1844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarnamespace clang { 1864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarnamespace ento { 1874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainartemplate<> struct ProgramStateTrait<SymbolSet> 1884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar: public ProgramStatePartialTrait<SymbolSet> { 1894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar static void *GDMIndex() { static int index = 0; return &index; } 1904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar}; 1914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 1924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 1934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 1944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// An AST check that diagnose when the class requires a -dealloc method and 1954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// is missing one. 1964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::checkASTDecl(const ObjCImplementationDecl *D, 1974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar AnalysisManager &Mgr, 1984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar BugReporter &BR) const { 1994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(Mgr.getLangOpts().getGC() != LangOptions::GCOnly); 2004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(!Mgr.getLangOpts().ObjCAutoRefCount); 2014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar initIdentifierInfoAndSelectors(Mgr.getASTContext()); 2024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 2034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCInterfaceDecl *ID = D->getClassInterface(); 2044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // If the class is known to have a lifecycle with a separate teardown method 2054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // then it may not require a -dealloc method. 2064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (classHasSeparateTeardown(ID)) 2074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 2084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 2094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Does the class contain any synthesized properties that are retainable? 2104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // If not, skip the check entirely. 2114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyImplDecl *PropImplRequiringRelease = nullptr; 2124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool HasOthers = false; 2134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar for (const auto *I : D->property_impls()) { 2144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (getDeallocReleaseRequirement(I) == ReleaseRequirement::MustRelease) { 2154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!PropImplRequiringRelease) 2164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar PropImplRequiringRelease = I; 2174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar else { 2184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar HasOthers = true; 2194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar break; 2204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 2214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 2228cb6fb3bd80d0b051f37c31d8658666361b5b7bbTed Kremenek } 2231eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!PropImplRequiringRelease) 225db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek return; 2261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2276bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines const ObjCMethodDecl *MD = nullptr; 2281eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 229db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek // Scan the instance methods for "dealloc". 230651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines for (const auto *I : D->instance_methods()) { 2314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (I->getSelector() == DeallocSel) { 232651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines MD = I; 233db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek break; 2341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump } 235db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek } 2361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 237db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek if (!MD) { // No dealloc found. 2384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const char* Name = "Missing -dealloc"; 2391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::string Buf; 2414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar llvm::raw_string_ostream OS(Buf); 2424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "'" << *D << "' lacks a 'dealloc' instance method but " 2434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar << "must release '" << *PropImplRequiringRelease->getPropertyIvarDecl() 2444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar << "'"; 2451eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (HasOthers) 2474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << " and others"; 2484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar PathDiagnosticLocation DLoc = 2494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar PathDiagnosticLocation::createBegin(D, BR.getSourceManager()); 2501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar BR.EmitBasicReport(D, this, Name, categories::CoreFoundationObjectiveC, 2524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS.str(), DLoc); 253db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek return; 254db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek } 2554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 2561eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// If this is the beginning of -dealloc, mark the values initially stored in 2584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// instance variables that must be released by the end of -dealloc 2594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// as unreleased in the state. 2604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::checkBeginFunction( 2614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const { 2624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar initIdentifierInfoAndSelectors(C.getASTContext()); 2631eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Only do this if the current method is -dealloc. 2654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal SelfVal; 2664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!isInInstanceDealloc(C, SelfVal)) 2674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 2681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef SelfSymbol = SelfVal.getAsSymbol(); 2704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 2714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const LocationContext *LCtx = C.getLocationContext(); 2724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef InitialState = C.getState(); 2734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 2744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef State = InitialState; 2754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 2764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>(); 2774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 2784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Symbols that must be released by the end of the -dealloc; 2794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolSet RequiredReleases = F.getEmptySet(); 2804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 2814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // If we're an inlined -dealloc, we should add our symbols to the existing 2824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // set from our subclass. 2834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (const SymbolSet *CurrSet = State->get<UnreleasedIvarMap>(SelfSymbol)) 2844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar RequiredReleases = *CurrSet; 2854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 2864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar for (auto *PropImpl : getContainingObjCImpl(LCtx)->property_impls()) { 2874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ReleaseRequirement Requirement = getDeallocReleaseRequirement(PropImpl); 2884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (Requirement != ReleaseRequirement::MustRelease) 2896f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek continue; 2901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal LVal = State->getLValue(PropImpl->getPropertyIvarDecl(), SelfVal); 2924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar Optional<Loc> LValLoc = LVal.getAs<Loc>(); 2934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!LValLoc) 2946f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek continue; 2951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal InitialVal = State->getSVal(LValLoc.getValue()); 2974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef Symbol = InitialVal.getAsSymbol(); 2984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!Symbol || !isa<SymbolRegionValue>(Symbol)) 2996f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek continue; 3006f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek 3014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Mark the value as requiring a release. 3024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar RequiredReleases = F.add(RequiredReleases, Symbol); 3034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 3044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!RequiredReleases.isEmpty()) { 3064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar State = State->set<UnreleasedIvarMap>(SelfSymbol, RequiredReleases); 3074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 3084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (State != InitialState) { 3104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar C.addTransition(State); 3114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 3124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 3134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Given a symbol for an ivar, return the ivar region it was loaded from. 3154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns nullptr if the instance symbol cannot be found. 3164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarconst ObjCIvarRegion * 3174967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarObjCDeallocChecker::getIvarRegionForIvarSymbol(SymbolRef IvarSym) const { 3184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return dyn_cast_or_null<ObjCIvarRegion>(IvarSym->getOriginRegion()); 3194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 3204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Given a symbol for an ivar, return a symbol for the instance containing 3224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// the ivar. Returns nullptr if the instance symbol cannot be found. 3234967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarSymbolRef 3244967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarObjCDeallocChecker::getInstanceSymbolFromIvarSymbol(SymbolRef IvarSym) const { 3254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCIvarRegion *IvarRegion = getIvarRegionForIvarSymbol(IvarSym); 3274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!IvarRegion) 3284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 3294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return IvarRegion->getSymbolicBase()->getSymbol(); 3314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 3324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// If we are in -dealloc or -dealloc is on the stack, handle the call if it is 3344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// a release or a nilling-out property setter. 3354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::checkPreObjCMessage( 3364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCMethodCall &M, CheckerContext &C) const { 3374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Only run if -dealloc is on the stack. 3384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal DeallocedInstance; 3394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!instanceDeallocIsOnStack(C, DeallocedInstance)) 3404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 3414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef ReleasedValue = nullptr; 3434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (M.getSelector() == ReleaseSel) { 3454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ReleasedValue = M.getReceiverSVal().getAsSymbol(); 3464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } else if (M.getSelector() == DeallocSel && !M.isReceiverSelfOrSuper()) { 3474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (diagnoseMistakenDealloc(M.getReceiverSVal().getAsSymbol(), M, C)) 3484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 3494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 3504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (ReleasedValue) { 3524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // An instance variable symbol was released with -release: 3534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // [_property release]; 3544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (diagnoseExtraRelease(ReleasedValue,M, C)) 3554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 3564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } else { 3574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // An instance variable symbol was released nilling out its property: 3584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // self.property = nil; 3594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ReleasedValue = getValueReleasedByNillingOut(M, C); 3604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 3614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!ReleasedValue) 3634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 3644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar transitionToReleaseValue(C, ReleasedValue); 3664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 3674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// If we are in -dealloc or -dealloc is on the stack, handle the call if it is 3694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// call to Block_release(). 3704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::checkPreCall(const CallEvent &Call, 3714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const { 3724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const IdentifierInfo *II = Call.getCalleeIdentifier(); 3734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (II != Block_releaseII) 3744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 3754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (Call.getNumArgs() != 1) 3774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 3784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef ReleasedValue = Call.getArgSVal(0).getAsSymbol(); 3804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!ReleasedValue) 3814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 3824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar transitionToReleaseValue(C, ReleasedValue); 3844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 3854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// If the message was a call to '[super dealloc]', diagnose any missing 3864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// releases. 3874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::checkPostObjCMessage( 3884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCMethodCall &M, CheckerContext &C) const { 3894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // We perform this check post-message so that if the super -dealloc 3904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // calls a helper method and that this class overrides, any ivars released in 3914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // the helper method will be recorded before checking. 3924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (isSuperDeallocMessage(M)) 3934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar diagnoseMissingReleases(C); 3944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 3954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 3964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Check for missing releases even when -dealloc does not call 3974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// '[super dealloc]'. 3984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::checkEndFunction( 3994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const { 4004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar diagnoseMissingReleases(C); 4014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 4024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Check for missing releases on early return. 4044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::checkPreStmt( 4054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ReturnStmt *RS, CheckerContext &C) const { 4064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar diagnoseMissingReleases(C); 4074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 4084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// When a symbol is assumed to be nil, remove it from the set of symbols 4104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// require to be nil. 4114967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarProgramStateRef ObjCDeallocChecker::evalAssume(ProgramStateRef State, SVal Cond, 4124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar bool Assumption) const { 4134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (State->get<UnreleasedIvarMap>().isEmpty()) 4144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar auto *CondBSE = dyn_cast_or_null<BinarySymExpr>(Cond.getAsSymExpr()); 4174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!CondBSE) 4184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar BinaryOperator::Opcode OpCode = CondBSE->getOpcode(); 4214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (Assumption) { 4224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (OpCode != BO_EQ) 4234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } else { 4254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (OpCode != BO_NE) 4264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 4284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef NullSymbol = nullptr; 4304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (auto *SIE = dyn_cast<SymIntExpr>(CondBSE)) { 4314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const llvm::APInt &RHS = SIE->getRHS(); 4324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (RHS != 0) 4334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar NullSymbol = SIE->getLHS(); 4354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } else if (auto *SIE = dyn_cast<IntSymExpr>(CondBSE)) { 4364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const llvm::APInt &LHS = SIE->getLHS(); 4374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (LHS != 0) 4384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar NullSymbol = SIE->getRHS(); 4404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } else { 4414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 4434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef InstanceSymbol = getInstanceSymbolFromIvarSymbol(NullSymbol); 4454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!InstanceSymbol) 4464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar State = removeValueRequiringRelease(State, InstanceSymbol, NullSymbol); 4494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 4524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// If a symbol escapes conservatively assume unseen code released it. 4544967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarProgramStateRef ObjCDeallocChecker::checkPointerEscape( 4554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef State, const InvalidatedSymbols &Escaped, 4564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const CallEvent *Call, PointerEscapeKind Kind) const { 4574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (State->get<UnreleasedIvarMap>().isEmpty()) 4594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Don't treat calls to '[super dealloc]' as escaping for the purposes 4624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // of this checker. Because the checker diagnoses missing releases in the 4634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // post-message handler for '[super dealloc], escaping here would cause 4644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // the checker to never warn. 4654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar auto *OMC = dyn_cast_or_null<ObjCMethodCall>(Call); 4664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (OMC && isSuperDeallocMessage(*OMC)) 4674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar for (const auto &Sym : Escaped) { 4704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!Call || (Call && !Call->isInSystemHeader())) { 4714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // If Sym is a symbol for an object with instance variables that 4724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // must be released, remove these obligations when the object escapes 4734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // unless via a call to a system function. System functions are 4744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // very unlikely to release instance variables on objects passed to them, 4754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // and are frequently called on 'self' in -dealloc (e.g., to remove 4764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // observers) -- we want to avoid false negatives from escaping on 4774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // them. 4784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar State = State->remove<UnreleasedIvarMap>(Sym); 4794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 4804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef InstanceSymbol = getInstanceSymbolFromIvarSymbol(Sym); 4834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!InstanceSymbol) 4844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar continue; 4854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar State = removeValueRequiringRelease(State, InstanceSymbol, Sym); 4874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 4884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 4904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 4914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Report any unreleased instance variables for the current instance being 4934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// dealloced. 4944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const { 4954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef State = C.getState(); 4964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 4974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal SelfVal; 4984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!isInInstanceDealloc(C, SelfVal)) 4994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 5004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const MemRegion *SelfRegion = SelfVal.castAs<loc::MemRegionVal>().getRegion(); 5024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const LocationContext *LCtx = C.getLocationContext(); 5034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ExplodedNode *ErrNode = nullptr; 5054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef SelfSym = SelfVal.getAsSymbol(); 5074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!SelfSym) 5084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 5094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const SymbolSet *OldUnreleased = State->get<UnreleasedIvarMap>(SelfSym); 5114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!OldUnreleased) 5124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 5134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolSet NewUnreleased = *OldUnreleased; 5154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>(); 5164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef InitialState = State; 5184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar for (auto *IvarSymbol : *OldUnreleased) { 5204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const TypedValueRegion *TVR = 5214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar cast<SymbolRegionValue>(IvarSymbol)->getRegion(); 5224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCIvarRegion *IvarRegion = cast<ObjCIvarRegion>(TVR); 5234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Don't warn if the ivar is not for this instance. 5254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (SelfRegion != IvarRegion->getSuperRegion()) 5266f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek continue; 5271eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCIvarDecl *IvarDecl = IvarRegion->getDecl(); 5294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Prevent an inlined call to -dealloc in a super class from warning 5304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // about the values the subclass's -dealloc should release. 5314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (IvarDecl->getContainingInterface() != 5324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar cast<ObjCMethodDecl>(LCtx->getDecl())->getClassInterface()) 533b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer continue; 5341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Prevents diagnosing multiple times for the same instance variable 5364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // at, for example, both a return and at the end of of the function. 5374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar NewUnreleased = F.remove(NewUnreleased, IvarSymbol); 5384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (State->getStateManager() 5404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar .getConstraintManager() 5414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar .isNull(State, IvarSymbol) 5424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar .isConstrainedTrue()) { 5434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar continue; 5444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 5454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // A missing release manifests as a leak, so treat as a non-fatal error. 5474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!ErrNode) 5484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ErrNode = C.generateNonFatalErrorNode(); 5494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // If we've already reached this node on another path, return without 5504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // diagnosing. 5514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!ErrNode) 5524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 5534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::string Buf; 5554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar llvm::raw_string_ostream OS(Buf); 5564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCInterfaceDecl *Interface = IvarDecl->getContainingInterface(); 5584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // If the class is known to have a lifecycle with teardown that is 5594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // separate from -dealloc, do not warn about missing releases. We 5604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // suppress here (rather than not tracking for instance variables in 5614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // such classes) because these classes are rare. 5624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (classHasSeparateTeardown(Interface)) 5634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 5644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ObjCImplDecl *ImplDecl = Interface->getImplementation(); 5664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyImplDecl *PropImpl = 5684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ImplDecl->FindPropertyImplIvarDecl(IvarDecl->getIdentifier()); 5691eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 5704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyDecl *PropDecl = PropImpl->getPropertyDecl(); 571590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks 5724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(PropDecl->getSetterKind() == ObjCPropertyDecl::Copy || 5734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar PropDecl->getSetterKind() == ObjCPropertyDecl::Retain); 5744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "The '" << *IvarDecl << "' ivar in '" << *ImplDecl 5764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar << "' was "; 5774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (PropDecl->getSetterKind() == ObjCPropertyDecl::Retain) 5794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "retained"; 5804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar else 5814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "copied"; 5824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << " by a synthesized property but not released" 5844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar " before '[super dealloc]'"; 5854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::unique_ptr<BugReport> BR( 5874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar new BugReport(*MissingReleaseBugType, OS.str(), ErrNode)); 5884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar C.emitReport(std::move(BR)); 5904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 5914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (NewUnreleased.isEmpty()) { 5934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar State = State->remove<UnreleasedIvarMap>(SelfSym); 5944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } else { 5954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar State = State->set<UnreleasedIvarMap>(SelfSym, NewUnreleased); 5964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 5974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 5984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (ErrNode) { 5994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar C.addTransition(State, ErrNode); 6004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } else if (State != InitialState) { 6014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar C.addTransition(State); 6024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 6034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Make sure that after checking in the top-most frame the list of 6054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // tracked ivars is empty. This is intended to detect accidental leaks in 6064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // the UnreleasedIvarMap program state. 6074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(!LCtx->inTopFrame() || State->get<UnreleasedIvarMap>().isEmpty()); 6084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 6094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Given a symbol, determine whether the symbol refers to an ivar on 6114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// the top-most deallocating instance. If so, find the property for that 6124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// ivar, if one exists. Otherwise return null. 6134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarconst ObjCPropertyImplDecl * 6144967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarObjCDeallocChecker::findPropertyOnDeallocatingInstance( 6154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef IvarSym, CheckerContext &C) const { 6164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal DeallocedInstance; 6174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!isInInstanceDealloc(C, DeallocedInstance)) 6184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 6194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Try to get the region from which the ivar value was loaded. 6214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar auto *IvarRegion = getIvarRegionForIvarSymbol(IvarSym); 6224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!IvarRegion) 6234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 6244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Don't try to find the property if the ivar was not loaded from the 6264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // given instance. 6274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (DeallocedInstance.castAs<loc::MemRegionVal>().getRegion() != 6284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar IvarRegion->getSuperRegion()) 6294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 6304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const LocationContext *LCtx = C.getLocationContext(); 6324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCIvarDecl *IvarDecl = IvarRegion->getDecl(); 6334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCImplDecl *Container = getContainingObjCImpl(LCtx); 6354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyImplDecl *PropImpl = 6364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar Container->FindPropertyImplIvarDecl(IvarDecl->getIdentifier()); 6374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return PropImpl; 6384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 6394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Emits a warning if the current context is -dealloc and ReleasedValue 6414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// must not be directly released in a -dealloc. Returns true if a diagnostic 6424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// was emitted. 6434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarbool ObjCDeallocChecker::diagnoseExtraRelease(SymbolRef ReleasedValue, 6444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCMethodCall &M, 6454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const { 6464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Try to get the region from which the the released value was loaded. 6474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Note that, unlike diagnosing for missing releases, here we don't track 6484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // values that must not be released in the state. This is because even if 6494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // these values escape, it is still an error under the rules of MRR to 6504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // release them in -dealloc. 6514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyImplDecl *PropImpl = 6524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar findPropertyOnDeallocatingInstance(ReleasedValue, C); 6534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!PropImpl) 6554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 6564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // If the ivar belongs to a property that must not be released directly 6584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // in dealloc, emit a warning. 6594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (getDeallocReleaseRequirement(PropImpl) != 6604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ReleaseRequirement::MustNotReleaseDirectly) { 6614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 6624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 6634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // If the property is readwrite but it shadows a read-only property in its 6654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // external interface, treat the property a read-only. If the outside 6664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // world cannot write to a property then the internal implementation is free 6674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // to make its own convention about whether the value is stored retained 6684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // or not. We look up the shadow here rather than in 6694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // getDeallocReleaseRequirement() because doing so can be expensive. 6704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyDecl *PropDecl = findShadowedPropertyDecl(PropImpl); 6714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (PropDecl) { 6724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (PropDecl->isReadOnly()) 6734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 6744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } else { 6754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar PropDecl = PropImpl->getPropertyDecl(); 6764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 6774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ExplodedNode *ErrNode = C.generateNonFatalErrorNode(); 6794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!ErrNode) 6804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 6814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::string Buf; 6834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar llvm::raw_string_ostream OS(Buf); 6844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(PropDecl->getSetterKind() == ObjCPropertyDecl::Weak || 6864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar (PropDecl->getSetterKind() == ObjCPropertyDecl::Assign && 6874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar !PropDecl->isReadOnly()) || 6884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar isReleasedByCIFilterDealloc(PropImpl) 6894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ); 6904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCImplDecl *Container = getContainingObjCImpl(C.getLocationContext()); 6924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "The '" << *PropImpl->getPropertyIvarDecl() 6934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar << "' ivar in '" << *Container; 6944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 6964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (isReleasedByCIFilterDealloc(PropImpl)) { 6974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "' will be released by '-[CIFilter dealloc]' but also released here"; 6984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } else { 6994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "' was synthesized for "; 7004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (PropDecl->getSetterKind() == ObjCPropertyDecl::Weak) 7024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "a weak"; 7034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar else 7044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "an assign, readwrite"; 7054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << " property but was released in 'dealloc'"; 7074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 7084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::unique_ptr<BugReport> BR( 7104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar new BugReport(*ExtraReleaseBugType, OS.str(), ErrNode)); 7114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar BR->addRange(M.getOriginExpr()->getSourceRange()); 7124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar C.emitReport(std::move(BR)); 7144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return true; 7164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 7174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Emits a warning if the current context is -dealloc and DeallocedValue 7194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// must not be directly dealloced in a -dealloc. Returns true if a diagnostic 7204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// was emitted. 7214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarbool ObjCDeallocChecker::diagnoseMistakenDealloc(SymbolRef DeallocedValue, 7224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCMethodCall &M, 7234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const { 7244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Find the property backing the instance variable that M 7264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // is dealloc'ing. 7274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyImplDecl *PropImpl = 7284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar findPropertyOnDeallocatingInstance(DeallocedValue, C); 7294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!PropImpl) 7304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 7314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (getDeallocReleaseRequirement(PropImpl) != 7334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ReleaseRequirement::MustRelease) { 7344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 7354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 7364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ExplodedNode *ErrNode = C.generateErrorNode(); 7384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!ErrNode) 7394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 7404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::string Buf; 7424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar llvm::raw_string_ostream OS(Buf); 7434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar OS << "'" << *PropImpl->getPropertyIvarDecl() 7454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar << "' should be released rather than deallocated"; 7464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::unique_ptr<BugReport> BR( 7484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar new BugReport(*MistakenDeallocBugType, OS.str(), ErrNode)); 7494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar BR->addRange(M.getOriginExpr()->getSourceRange()); 7504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar C.emitReport(std::move(BR)); 7524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return true; 7544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 7554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7564967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarObjCDeallocChecker::ObjCDeallocChecker() 7574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar : NSObjectII(nullptr), SenTestCaseII(nullptr), XCTestCaseII(nullptr), 7584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CIFilterII(nullptr) { 7594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar MissingReleaseBugType.reset( 7614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar new BugType(this, "Missing ivar release (leak)", 7624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar categories::MemoryCoreFoundationObjectiveC)); 7634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ExtraReleaseBugType.reset( 7654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar new BugType(this, "Extra ivar release", 7664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar categories::MemoryCoreFoundationObjectiveC)); 7674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar MistakenDeallocBugType.reset( 7694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar new BugType(this, "Mistaken dealloc", 7704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar categories::MemoryCoreFoundationObjectiveC)); 7714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 7724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::initIdentifierInfoAndSelectors( 7744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ASTContext &Ctx) const { 7754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (NSObjectII) 7764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 7774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar NSObjectII = &Ctx.Idents.get("NSObject"); 7794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SenTestCaseII = &Ctx.Idents.get("SenTestCase"); 7804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar XCTestCaseII = &Ctx.Idents.get("XCTestCase"); 7814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar Block_releaseII = &Ctx.Idents.get("_Block_release"); 7824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CIFilterII = &Ctx.Idents.get("CIFilter"); 7834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar IdentifierInfo *DeallocII = &Ctx.Idents.get("dealloc"); 7854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar IdentifierInfo *ReleaseII = &Ctx.Idents.get("release"); 7864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar DeallocSel = Ctx.Selectors.getSelector(0, &DeallocII); 7874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ReleaseSel = Ctx.Selectors.getSelector(0, &ReleaseII); 7884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 7894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns true if M is a call to '[super dealloc]'. 7914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarbool ObjCDeallocChecker::isSuperDeallocMessage( 7924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCMethodCall &M) const { 7934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (M.getOriginExpr()->getReceiverKind() != ObjCMessageExpr::SuperInstance) 7944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 7954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return M.getSelector() == DeallocSel; 7974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 7984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 7994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns the ObjCImplDecl containing the method declaration in LCtx. 8004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarconst ObjCImplDecl * 8014967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarObjCDeallocChecker::getContainingObjCImpl(const LocationContext *LCtx) const { 8024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar auto *MD = cast<ObjCMethodDecl>(LCtx->getDecl()); 8034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return cast<ObjCImplDecl>(MD->getDeclContext()); 8044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 8054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns the property that shadowed by PropImpl if one exists and 8074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// nullptr otherwise. 8084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarconst ObjCPropertyDecl *ObjCDeallocChecker::findShadowedPropertyDecl( 8094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyImplDecl *PropImpl) const { 8104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyDecl *PropDecl = PropImpl->getPropertyDecl(); 8114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Only readwrite properties can shadow. 8134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (PropDecl->isReadOnly()) 8144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 8154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar auto *CatDecl = dyn_cast<ObjCCategoryDecl>(PropDecl->getDeclContext()); 8174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Only class extensions can contain shadowing properties. 8194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!CatDecl || !CatDecl->IsClassExtension()) 8204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 8214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar IdentifierInfo *ID = PropDecl->getIdentifier(); 8234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar DeclContext::lookup_result R = CatDecl->getClassInterface()->lookup(ID); 8244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) { 8254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar auto *ShadowedPropDecl = dyn_cast<ObjCPropertyDecl>(*I); 8264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!ShadowedPropDecl) 8274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar continue; 8284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (ShadowedPropDecl->isInstanceProperty()) { 8304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(ShadowedPropDecl->isReadOnly()); 8314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return ShadowedPropDecl; 8326f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek } 8336f2bb36d254239622ab7c4fbb25023871448e2a3Ted Kremenek } 8344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 836db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek} 837db09a4dee28a4515438af60f2d2b4a83e4965c31Ted Kremenek 8384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Add a transition noting the release of the given value. 8394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ObjCDeallocChecker::transitionToReleaseValue(CheckerContext &C, 8404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef Value) const { 8414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(Value); 8424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolRef InstanceSym = getInstanceSymbolFromIvarSymbol(Value); 8434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!InstanceSym) 8444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 8454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef InitialState = C.getState(); 8467dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis 8474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef ReleasedState = 8484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar removeValueRequiringRelease(InitialState, InstanceSym, Value); 8494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (ReleasedState != InitialState) { 8514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar C.addTransition(ReleasedState); 8527dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis } 8537dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis} 8547dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis 8554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Remove the Value requiring a release from the tracked set for 8564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Instance and return the resultant state. 8574967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarProgramStateRef ObjCDeallocChecker::removeValueRequiringRelease( 8584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef State, SymbolRef Instance, SymbolRef Value) const { 8594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(Instance); 8604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(Value); 8614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCIvarRegion *RemovedRegion = getIvarRegionForIvarSymbol(Value); 8624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!RemovedRegion) 8634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 8644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const SymbolSet *Unreleased = State->get<UnreleasedIvarMap>(Instance); 8664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!Unreleased) 8674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State; 8684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Mark the value as no longer requiring a release. 8704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>(); 8714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SymbolSet NewUnreleased = *Unreleased; 8724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar for (auto &Sym : *Unreleased) { 8734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCIvarRegion *UnreleasedRegion = getIvarRegionForIvarSymbol(Sym); 8744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(UnreleasedRegion); 8754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (RemovedRegion->getDecl() == UnreleasedRegion->getDecl()) { 8764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar NewUnreleased = F.remove(NewUnreleased, Sym); 8774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 8784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 8794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (NewUnreleased.isEmpty()) { 8814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State->remove<UnreleasedIvarMap>(Instance); 8824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 8834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return State->set<UnreleasedIvarMap>(Instance, NewUnreleased); 8854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 8864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Determines whether the instance variable for \p PropImpl must or must not be 8884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// released in -dealloc or whether it cannot be determined. 8894967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarReleaseRequirement ObjCDeallocChecker::getDeallocReleaseRequirement( 8904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyImplDecl *PropImpl) const { 8914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCIvarDecl *IvarDecl; 8924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyDecl *PropDecl; 8934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!isSynthesizedRetainableProperty(PropImpl, &IvarDecl, &PropDecl)) 8944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return ReleaseRequirement::Unknown; 8954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ObjCPropertyDecl::SetterKind SK = PropDecl->getSetterKind(); 8974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 8984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar switch (SK) { 8994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Retain and copy setters retain/copy their values before storing and so 9004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // the value in their instance variables must be released in -dealloc. 9014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar case ObjCPropertyDecl::Retain: 9024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar case ObjCPropertyDecl::Copy: 9034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (isReleasedByCIFilterDealloc(PropImpl)) 9044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return ReleaseRequirement::MustNotReleaseDirectly; 9054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return ReleaseRequirement::MustRelease; 9074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar case ObjCPropertyDecl::Weak: 9094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return ReleaseRequirement::MustNotReleaseDirectly; 9104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar case ObjCPropertyDecl::Assign: 9124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // It is common for the ivars for read-only assign properties to 9134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // always be stored retained, so their release requirement cannot be 9144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // be determined. 9154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (PropDecl->isReadOnly()) 9164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return ReleaseRequirement::Unknown; 9174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return ReleaseRequirement::MustNotReleaseDirectly; 9194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 9204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar llvm_unreachable("Unrecognized setter kind"); 9214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 9224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns the released value if M is a call a setter that releases 9244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// and nils out its underlying instance variable. 9254967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarSymbolRef 9264967a710c84587c654b56c828382219c3937dacbPirama Arumuga NainarObjCDeallocChecker::getValueReleasedByNillingOut(const ObjCMethodCall &M, 9274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar CheckerContext &C) const { 9284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal ReceiverVal = M.getReceiverSVal(); 9294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!ReceiverVal.isValid()) 9304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 9314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (M.getNumArgs() == 0) 9334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 9344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!M.getArgExpr(0)->getType()->isObjCRetainableType()) 9364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 9374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Is the first argument nil? 9394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal Arg = M.getArgSVal(0); 9404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef notNilState, nilState; 9414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar std::tie(notNilState, nilState) = 9424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar M.getState()->assume(Arg.castAs<DefinedOrUnknownSVal>()); 9434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!(nilState && !notNilState)) 9444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 9454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyDecl *Prop = M.getAccessedProperty(); 9474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!Prop) 9484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 9494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ObjCIvarDecl *PropIvarDecl = Prop->getPropertyIvarDecl(); 9514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!PropIvarDecl) 9524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 9534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef State = C.getState(); 9554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal LVal = State->getLValue(PropIvarDecl, ReceiverVal); 9574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar Optional<Loc> LValLoc = LVal.getAs<Loc>(); 9584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!LValLoc) 9594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return nullptr; 9604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal CurrentValInIvar = State->getSVal(LValLoc.getValue()); 9624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return CurrentValInIvar.getAsSymbol(); 9634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 9644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns true if the current context is a call to -dealloc and false 9664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// otherwise. If true, it also sets SelfValOut to the value of 9674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// 'self'. 9684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarbool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C, 9694967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal &SelfValOut) const { 9704967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return isInInstanceDealloc(C, C.getLocationContext(), SelfValOut); 9714967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 9724967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9734967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns true if LCtx is a call to -dealloc and false 9744967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// otherwise. If true, it also sets SelfValOut to the value of 9754967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// 'self'. 9764967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarbool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C, 9774967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const LocationContext *LCtx, 9784967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal &SelfValOut) const { 9794967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar auto *MD = dyn_cast<ObjCMethodDecl>(LCtx->getDecl()); 9804967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!MD || !MD->isInstanceMethod() || MD->getSelector() != DeallocSel) 9814967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 9824967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9834967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl(); 9844967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(SelfDecl && "No self in -dealloc?"); 9854967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9864967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar ProgramStateRef State = C.getState(); 9874967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SelfValOut = State->getSVal(State->getRegion(SelfDecl, LCtx)); 9884967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return true; 9894967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 9904967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9914967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns true if there is a call to -dealloc anywhere on the stack and false 9924967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// otherwise. If true, it also sets InstanceValOut to the value of 9934967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// 'self' in the frame for -dealloc. 9944967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarbool ObjCDeallocChecker::instanceDeallocIsOnStack(const CheckerContext &C, 9954967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar SVal &InstanceValOut) const { 9964967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const LocationContext *LCtx = C.getLocationContext(); 9974967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 9984967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar while (LCtx) { 9994967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (isInInstanceDealloc(C, LCtx, InstanceValOut)) 10004967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return true; 10014967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10024967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar LCtx = LCtx->getParent(); 10034967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 10044967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10054967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 10064967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 10074967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10084967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Returns true if the ID is a class in which which is known to have 10094967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// a separate teardown lifecycle. In this case, -dealloc warnings 10104967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// about missing releases should be suppressed. 10114967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarbool ObjCDeallocChecker::classHasSeparateTeardown( 10124967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCInterfaceDecl *ID) const { 10134967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // Suppress if the class is not a subclass of NSObject. 10144967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar for ( ; ID ; ID = ID->getSuperClass()) { 10154967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar IdentifierInfo *II = ID->getIdentifier(); 10164967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10174967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (II == NSObjectII) 10184967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 10194967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10204967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // FIXME: For now, ignore classes that subclass SenTestCase and XCTestCase, 10214967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // as these don't need to implement -dealloc. They implement tear down in 10224967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // another way, which we should try and catch later. 10234967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // http://llvm.org/bugs/show_bug.cgi?id=3187 10244967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (II == XCTestCaseII || II == SenTestCaseII) 10254967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return true; 10264967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 10274967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10284967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return true; 10294967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 10304967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10314967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// The -dealloc method in CIFilter highly unusual in that is will release 10324967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// instance variables belonging to its *subclasses* if the variable name 10334967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// starts with "input" or backs a property whose name starts with "input". 10344967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// Subclasses should not release these ivars in their own -dealloc method -- 10354967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// doing so could result in an over release. 10364967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// 10374967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// This method returns true if the property will be released by 10384967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar/// -[CIFilter dealloc]. 10394967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarbool ObjCDeallocChecker::isReleasedByCIFilterDealloc( 10404967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCPropertyImplDecl *PropImpl) const { 10414967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar assert(PropImpl->getPropertyIvarDecl()); 10424967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar StringRef PropName = PropImpl->getPropertyDecl()->getName(); 10434967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar StringRef IvarName = PropImpl->getPropertyIvarDecl()->getName(); 10444967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10454967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const char *ReleasePrefix = "input"; 10464967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (!(PropName.startswith(ReleasePrefix) || 10474967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar IvarName.startswith(ReleasePrefix))) { 10484967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 10494967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 10504967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10514967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const ObjCInterfaceDecl *ID = 10524967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar PropImpl->getPropertyIvarDecl()->getContainingInterface(); 10534967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar for ( ; ID ; ID = ID->getSuperClass()) { 10544967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar IdentifierInfo *II = ID->getIdentifier(); 10554967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (II == CIFilterII) 10564967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return true; 10574967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar } 10584967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10594967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return false; 10604967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar} 10614967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10624967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainarvoid ento::registerObjCDeallocChecker(CheckerManager &Mgr) { 10634967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar const LangOptions &LangOpts = Mgr.getLangOpts(); 10644967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar // These checker only makes sense under MRR. 10654967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar if (LangOpts.getGC() == LangOptions::GCOnly || LangOpts.ObjCAutoRefCount) 10664967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar return; 10674967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar 10684967a710c84587c654b56c828382219c3937dacbPirama Arumuga Nainar Mgr.registerChecker<ObjCDeallocChecker>(); 10697dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis} 1070