forked from OSchip/llvm-project
[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:
parent
41e9b1d559
commit
8a5a094ec5
|
@ -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>()) {
|
||||||
|
|
|
@ -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}}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue