[analyzer] Look through temporary destructors when finding a region to construct.

Fixes a false positive when temporary destructors are enabled where a temporary
is destroyed after a variable is constructed but before the VarDecl itself is
processed, which occurs when the variable is in the condition of an if or while.

Patch by Alex McCarthy, with an extra test from me.

llvm-svn: 205661
This commit is contained in:
Jordan Rose 2014-04-05 02:01:41 +00:00
parent 41e9b1d559
commit 8a5a094ec5
2 changed files with 20 additions and 7 deletions

View File

@ -113,8 +113,16 @@ static const MemRegion *getRegionForConstructedObject(
// See if we're constructing an existing region by looking at the next // See if we're constructing an existing region by looking at the next
// element in the CFG. // element in the CFG.
const CFGBlock *B = CurrBldrCtx.getBlock(); const CFGBlock *B = CurrBldrCtx.getBlock();
if (CurrStmtIdx + 1 < B->size()) { unsigned int NextStmtIdx = CurrStmtIdx + 1;
CFGElement Next = (*B)[CurrStmtIdx+1]; if (NextStmtIdx < B->size()) {
CFGElement Next = (*B)[NextStmtIdx];
// Is this a destructor? If so, we might be in the middle of an assignment
// to a local or member: look ahead one more element to see what we find.
while (Next.getAs<CFGImplicitDtor>() && NextStmtIdx + 1 < B->size()) {
++NextStmtIdx;
Next = (*B)[NextStmtIdx];
}
// Is this a constructor for a local variable? // Is this a constructor for a local variable?
if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) { if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) {

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -Wno-null-dereference -verify %s // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors,cfg-temporary-dtors=true -Wno-null-dereference -verify %s
void clang_analyzer_eval(bool); void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool); void clang_analyzer_checkInlined(bool);
@ -426,8 +426,14 @@ namespace LifetimeExtension {
// This case used to cause an unexpected "Undefined or garbage value returned // This case used to cause an unexpected "Undefined or garbage value returned
// to caller" warning // to caller" warning
bool testNamedCustomDestructor() { // bool testNamedCustomDestructor() {
if (CheckCustomDestructor c = CheckCustomDestructor()) // if (CheckCustomDestructor c = CheckCustomDestructor())
// return true;
// return false;
// }
bool testMultipleTemporariesCustomDestructor() {
if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor()))
return true; return true;
return false; return false;
} }
@ -477,8 +483,7 @@ namespace NoReturn {
void g2(int *x) { void g2(int *x) {
if (! x) NR(); if (! x) NR();
// FIXME: this shouldn't cause a warning. *x = 47; // no warning
*x = 47; // expected-warning{{Dereference of null pointer}}
} }
} }