Author: dcoughlin Date: Mon Feb 29 17:57:10 2016 New Revision: 262272 URL: http://llvm.org/viewvc/llvm-project?rev=262272&view=rev Log: [analyzer] Teach CheckObjCDealloc about Block_release().
It now treats Block_release(b) as a release in addition to [b release]. Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp cfe/trunk/test/Analysis/DeallocMissingRelease.m cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp?rev=262272&r1=262271&r2=262272&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp Mon Feb 29 17:57:10 2016 @@ -92,12 +92,13 @@ namespace { class ObjCDeallocChecker : public Checker<check::ASTDecl<ObjCImplementationDecl>, check::PreObjCMessage, check::PostObjCMessage, + check::PreCall, check::BeginFunction, check::EndFunction, eval::Assume, check::PointerEscape, check::PreStmt<ReturnStmt>> { - mutable IdentifierInfo *NSObjectII, *SenTestCaseII; + mutable IdentifierInfo *NSObjectII, *SenTestCaseII, *Block_releaseII; mutable Selector DeallocSel, ReleaseSel; std::unique_ptr<BugType> MissingReleaseBugType; @@ -110,6 +111,7 @@ public: BugReporter &BR) const; void checkBeginFunction(CheckerContext &Ctx) const; void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond, @@ -152,6 +154,7 @@ private: const ObjCPropertyDecl * findShadowedPropertyDecl(const ObjCPropertyImplDecl *PropImpl) const; + void transitionToReleaseValue(CheckerContext &C, SymbolRef Value) const; ProgramStateRef removeValueRequiringRelease(ProgramStateRef State, SymbolRef InstanceSym, SymbolRef ValueSym) const; @@ -341,19 +344,26 @@ void ObjCDeallocChecker::checkPreObjCMes if (!ReleasedValue) return; - SymbolRef InstanceSym = getInstanceSymbolFromIvarSymbol(ReleasedValue); - if (!InstanceSym) + transitionToReleaseValue(C, ReleasedValue); +} + +/// If we are in -dealloc or -dealloc is on the stack, handle the call if it is +/// call to Block_release(). +void ObjCDeallocChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + const IdentifierInfo *II = Call.getCalleeIdentifier(); + if (II != Block_releaseII) return; - ProgramStateRef InitialState = C.getState(); - ProgramStateRef ReleasedState = - removeValueRequiringRelease(InitialState, InstanceSym, ReleasedValue); + if (Call.getNumArgs() != 1) + return; - if (ReleasedState != InitialState) { - C.addTransition(ReleasedState); - } -} + SymbolRef ReleasedValue = Call.getArgSVal(0).getAsSymbol(); + if (!ReleasedValue) + return; + transitionToReleaseValue(C, ReleasedValue); +} /// If the message was a call to '[super dealloc]', diagnose any missing /// releases. void ObjCDeallocChecker::checkPostObjCMessage( @@ -684,6 +694,7 @@ void ObjCDeallocChecker::initIdentifierI NSObjectII = &Ctx.Idents.get("NSObject"); SenTestCaseII = &Ctx.Idents.get("SenTestCase"); + Block_releaseII = &Ctx.Idents.get("_Block_release"); IdentifierInfo *DeallocII = &Ctx.Idents.get("dealloc"); IdentifierInfo *ReleaseII = &Ctx.Idents.get("release"); @@ -739,6 +750,23 @@ const ObjCPropertyDecl *ObjCDeallocCheck return nullptr; } +/// Add a transition noting the release of the given value. +void ObjCDeallocChecker::transitionToReleaseValue(CheckerContext &C, + SymbolRef Value) const { + assert(Value); + SymbolRef InstanceSym = getInstanceSymbolFromIvarSymbol(Value); + if (!InstanceSym) + return; + ProgramStateRef InitialState = C.getState(); + + ProgramStateRef ReleasedState = + removeValueRequiringRelease(InitialState, InstanceSym, Value); + + if (ReleasedState != InitialState) { + C.addTransition(ReleasedState); + } +} + /// Remove the Value requiring a release from the tracked set for /// Instance and return the resultant state. ProgramStateRef ObjCDeallocChecker::removeValueRequiringRelease( Modified: cfe/trunk/test/Analysis/DeallocMissingRelease.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/DeallocMissingRelease.m?rev=262272&r1=262271&r2=262272&view=diff ============================================================================== --- cfe/trunk/test/Analysis/DeallocMissingRelease.m (original) +++ cfe/trunk/test/Analysis/DeallocMissingRelease.m Mon Feb 29 17:57:10 2016 @@ -125,6 +125,9 @@ void (^_blockPropertyIvar)(void); } @property (copy) void (^blockProperty)(void); +@property (copy) void (^blockProperty2)(void); +@property (copy) void (^blockProperty3)(void); + @end @implementation MyPropertyClass4 @@ -132,6 +135,9 @@ - (void)dealloc { #if NON_ARC + [_blockProperty2 release]; + Block_release(_blockProperty3); + [super dealloc]; // expected-warning {{The '_blockPropertyIvar' ivar in 'MyPropertyClass4' was copied by a synthesized property but not released before '[super dealloc]'}} #endif } Modified: cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h?rev=262272&r1=262271&r2=262272&view=diff ============================================================================== --- cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h (original) +++ cfe/trunk/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h Mon Feb 29 17:57:10 2016 @@ -27,3 +27,6 @@ typedef signed char BOOL; @end typedef struct objc_selector *SEL; + +void _Block_release(const void *aBlock); +#define Block_release(...) _Block_release((const void *)(__VA_ARGS__)) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits