diff options
author | Anna Zaks <ganna@apple.com> | 2014-06-13 23:47:38 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2014-06-13 23:47:38 +0000 |
commit | a6fea1386feb3e07ec77b936ff17ead38d93f0ac (patch) | |
tree | 469a0c04e76390df99a8246747bc439ecd6ad265 /clang | |
parent | e287ef847ab1862015d24fbab1b2b1ea10efcd13 (diff) | |
download | bcm5719-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.h | 2 | ||||
-rw-r--r-- | clang/lib/Analysis/CFG.cpp | 4 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp | 23 | ||||
-rw-r--r-- | clang/test/Analysis/objc-radar17039661.m | 60 |
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; + } +} |