summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorDevin Coughlin <dcoughlin@apple.com>2016-02-29 23:57:10 +0000
committerDevin Coughlin <dcoughlin@apple.com>2016-02-29 23:57:10 +0000
commit093594938bf5c46a5fb4b7b3ea157eb269d8f885 (patch)
treefcada07b69a68aebea2613b9f5f540f6a2bc0747 /clang
parent46d4aa211ff9e84d8f71aafe818804758133b8aa (diff)
downloadbcm5719-llvm-093594938bf5c46a5fb4b7b3ea157eb269d8f885.tar.gz
bcm5719-llvm-093594938bf5c46a5fb4b7b3ea157eb269d8f885.zip
[analyzer] Teach CheckObjCDealloc about Block_release().
It now treats Block_release(b) as a release in addition to [b release]. llvm-svn: 262272
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp48
-rw-r--r--clang/test/Analysis/DeallocMissingRelease.m6
-rw-r--r--clang/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h3
3 files changed, 47 insertions, 10 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index f72a1aeb8a9..ea64d9b3d73 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -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::checkPreObjCMessage(
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::initIdentifierInfoAndSelectors(
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 *ObjCDeallocChecker::findShadowedPropertyDecl(
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(
diff --git a/clang/test/Analysis/DeallocMissingRelease.m b/clang/test/Analysis/DeallocMissingRelease.m
index bb67e436b2b..ff7c4e5971c 100644
--- a/clang/test/Analysis/DeallocMissingRelease.m
+++ b/clang/test/Analysis/DeallocMissingRelease.m
@@ -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
}
diff --git a/clang/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h b/clang/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h
index 0b9888a076a..9850aec6ee8 100644
--- a/clang/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h
+++ b/clang/test/Analysis/Inputs/system-header-simulator-for-objc-dealloc.h
@@ -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__))
OpenPOWER on IntegriCloud