summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2014-06-13 23:47:38 +0000
committerAnna Zaks <ganna@apple.com>2014-06-13 23:47:38 +0000
commita6fea1386feb3e07ec77b936ff17ead38d93f0ac (patch)
tree469a0c04e76390df99a8246747bc439ecd6ad265 /clang
parente287ef847ab1862015d24fbab1b2b1ea10efcd13 (diff)
downloadbcm5719-llvm-a6fea1386feb3e07ec77b936ff17ead38d93f0ac.tar.gz
bcm5719-llvm-a6fea1386feb3e07ec77b936ff17ead38d93f0ac.zip
Fix a crash in Retain Count checker error reporting
Fixes a crash in Retain Count checker error reporting logic by handing the allocation statement retrieval from a BlockEdge program point. Also added a simple CFG dump routine for debugging. llvm-svn: 210960
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Analysis/CFG.h2
-rw-r--r--clang/lib/Analysis/CFG.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp23
-rw-r--r--clang/test/Analysis/objc-radar17039661.m60
4 files changed, 84 insertions, 5 deletions
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index 7909fdc09cb..891fb90691f 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -641,6 +641,8 @@ public:
CFG *getParent() const { return Parent; }
+ void dump() const;
+
void dump(const CFG *cfg, const LangOptions &LO, bool ShowColors = false) const;
void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO,
bool ShowColors) const;
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 61e5f5acf01..d6361e8767c 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -4356,6 +4356,10 @@ void CFGBlock::dump(const CFG* cfg, const LangOptions &LO,
print(llvm::errs(), cfg, LO, ShowColors);
}
+void CFGBlock::dump() const {
+ dump(getParent(), LangOptions(), false);
+}
+
/// print - A simple pretty printer of a CFGBlock that outputs to an ostream.
/// Generally this will only be called from CFG::print.
void CFGBlock::print(raw_ostream &OS, const CFG* cfg,
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 0c130fe833b..eb699d69408 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -2340,14 +2340,27 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
// Get the SourceLocation for the allocation site.
// FIXME: This will crash the analyzer if an allocation comes from an
- // implicit call. (Currently there are no such allocations in Cocoa, though.)
- const Stmt *AllocStmt;
+ // implicit call (ex: a destructor call).
+ // (Currently there are no such allocations in Cocoa, though.)
+ const Stmt *AllocStmt = 0;
ProgramPoint P = AllocNode->getLocation();
if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
AllocStmt = Exit->getCalleeContext()->getCallSite();
- else
- AllocStmt = P.castAs<PostStmt>().getStmt();
- assert(AllocStmt && "All allocations must come from explicit calls");
+ else {
+ // We are going to get a BlockEdge when the leak and allocation happen in
+ // different, non-nested frames (contexts). For example, the case where an
+ // allocation happens in a block that captures a reference to it and
+ // that reference is overwritten/dropped by another call to the block.
+ if (Optional<BlockEdge> Edge = P.getAs<BlockEdge>()) {
+ if (Optional<CFGStmt> St = Edge->getDst()->front().getAs<CFGStmt>()) {
+ AllocStmt = St->getStmt();
+ }
+ }
+ else {
+ AllocStmt = P.castAs<PostStmt>().getStmt();
+ }
+ }
+ assert(AllocStmt && "Cannot find allocation statement");
PathDiagnosticLocation AllocLocation =
PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
diff --git a/clang/test/Analysis/objc-radar17039661.m b/clang/test/Analysis/objc-radar17039661.m
new file mode 100644
index 00000000000..ec4f19d2da3
--- /dev/null
+++ b/clang/test/Analysis/objc-radar17039661.m
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -verify -fblocks %s
+
+@class NSString;
+typedef long NSInteger;
+typedef unsigned char BOOL;
+@interface NSObject {}
++(id)alloc;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+-(id)retain;
+@end
+@interface NSNumber : NSObject
++ (NSNumber *)numberWithInteger:(NSInteger)value __attribute__((availability(ios,introduced=2.0)));
+@end
+
+NSInteger *inoutIntegerValueGlobal;
+NSInteger *inoutIntegerValueGlobal2;
+NSString *traitNameGlobal;
+static BOOL cond;
+
+static inline void reallyPerformAction(void (^integerHandler)(NSInteger *inoutIntegerValue, NSString *traitName)) {
+ integerHandler(inoutIntegerValueGlobal, traitNameGlobal);
+ integerHandler(inoutIntegerValueGlobal2,traitNameGlobal);
+}
+
+static inline BOOL performAction(NSNumber *(^action)(NSNumber *traitValue)) {
+ __attribute__((__blocks__(byref))) BOOL didFindTrait = 0;
+ reallyPerformAction(^(NSInteger *inoutIntegerValue,NSString *traitName) {
+
+ if (cond) {
+
+ NSNumber *traitValue = @(*inoutIntegerValue);
+
+ NSNumber *newTraitValue = action(traitValue);
+
+ if (traitValue != newTraitValue) {
+ *inoutIntegerValue = newTraitValue ? *inoutIntegerValue : *inoutIntegerValue;
+ }
+ didFindTrait = 1;
+ }
+
+ });
+ return didFindTrait;
+}
+
+void runTest() {
+ __attribute__((__blocks__(byref))) NSNumber *builtinResult = ((NSNumber *)0);
+ BOOL wasBuiltinTrait = performAction(^(NSNumber *traitValue) {
+ builtinResult = [traitValue retain]; // expected-warning {{Potential leak of an object}}
+
+ return traitValue;
+ });
+ if (wasBuiltinTrait) {
+ [builtinResult autorelease];
+ return;
+ } else {
+ return;
+ }
+}
OpenPOWER on IntegriCloud