[analyzer] Look for allocation site in the parent frames as well as the current one.

Instead of handling edge cases (mostly involving blocks), where we have difficulty finding
an allocation statement, allow the allocation site to be in a parent node.

Previously we assumed that the allocation site can always be found in the same frame
as allocation, but there are scenarios in which an element is leaked in a child
frame but is allocated in the parent.

llvm-svn: 228247
This commit is contained in:
Anna Zaks 2015-02-05 01:02:53 +00:00
parent 7b6da65990
commit 486a0ff4b7
4 changed files with 1201 additions and 31 deletions

View File

@ -499,9 +499,11 @@ MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
while (N) {
if (!N->getState()->get<AllocatedData>(Sym))
break;
// Allocation node, is the last node in the current context in which the
// symbol was tracked.
if (N->getLocationContext() == LeakContext)
// Allocation node, is the last node in the current or parent context in
// which the symbol was tracked.
const LocationContext *NContext = N->getLocationContext();
if (NContext == LeakContext ||
NContext->isParentOf(LeakContext))
AllocNode = N;
N = N->pred_empty() ? nullptr : *(N->pred_begin());
}

View File

@ -1801,9 +1801,11 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
}
}
// Allocation node, is the last node in the current context in which the
// symbol was tracked.
if (N->getLocationContext() == LeakContext)
// Allocation node, is the last node in the current or parent context in
// which the symbol was tracked.
const LocationContext *NContext = N->getLocationContext();
if (NContext == LeakContext ||
NContext->isParentOf(LeakContext))
AllocNode = N;
N = N->pred_empty() ? nullptr : *(N->pred_begin());
}

View File

@ -2190,7 +2190,7 @@ static AllocationInfo
GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
SymbolRef Sym) {
const ExplodedNode *AllocationNode = N;
const ExplodedNode *AllocationNodeInCurrentContext = N;
const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
const MemRegion *FirstBinding = nullptr;
const LocationContext *LeakContext = N->getLocationContext();
@ -2220,10 +2220,15 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
// AllocationNode is the last node in which the symbol was tracked.
AllocationNode = N;
// AllocationNodeInCurrentContext, is the last node in the current context
// in which the symbol was tracked.
if (NContext == LeakContext)
AllocationNodeInCurrentContext = N;
// AllocationNodeInCurrentContext, is the last node in the current or
// parent context in which the symbol was tracked.
//
// Note that the allocation site might be in the parent conext. 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 (NContext == LeakContext || NContext->isParentOf(LeakContext))
AllocationNodeInCurrentOrParentContext = N;
// Find the last init that was called on the given symbol and store the
// init method's location context.
@ -2261,7 +2266,7 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
FirstBinding = nullptr;
}
return AllocationInfo(AllocationNodeInCurrentContext,
return AllocationInfo(AllocationNodeInCurrentOrParentContext,
FirstBinding,
InterestingMethodContext);
}
@ -2392,20 +2397,8 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
ProgramPoint P = AllocNode->getLocation();
if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
AllocStmt = Exit->getCalleeContext()->getCallSite();
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();
}
}
else
AllocStmt = P.castAs<PostStmt>().getStmt();
assert(AllocStmt && "Cannot find allocation statement");
PathDiagnosticLocation AllocLocation =

File diff suppressed because it is too large Load Diff