forked from OSchip/llvm-project
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
This commit is contained in:
parent
e287ef847a
commit
a6fea1386f
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue