From 8a5a094ec5a4e23e5e7a2862e2ada60ec82f1f7b Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Sat, 5 Apr 2014 02:01:41 +0000 Subject: [PATCH] [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 --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 12 ++++++++++-- clang/test/Analysis/dtor.cpp | 15 ++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 52fe156e3525..e1eb7281479f 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -113,8 +113,16 @@ static const MemRegion *getRegionForConstructedObject( // See if we're constructing an existing region by looking at the next // element in the CFG. const CFGBlock *B = CurrBldrCtx.getBlock(); - if (CurrStmtIdx + 1 < B->size()) { - CFGElement Next = (*B)[CurrStmtIdx+1]; + unsigned int NextStmtIdx = 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() && NextStmtIdx + 1 < B->size()) { + ++NextStmtIdx; + Next = (*B)[NextStmtIdx]; + } // Is this a constructor for a local variable? if (Optional StmtElem = Next.getAs()) { diff --git a/clang/test/Analysis/dtor.cpp b/clang/test/Analysis/dtor.cpp index dbb950eda0f7..e410fc9083a0 100644 --- a/clang/test/Analysis/dtor.cpp +++ b/clang/test/Analysis/dtor.cpp @@ -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_checkInlined(bool); @@ -426,8 +426,14 @@ namespace LifetimeExtension { // This case used to cause an unexpected "Undefined or garbage value returned // to caller" warning - bool testNamedCustomDestructor() { - if (CheckCustomDestructor c = CheckCustomDestructor()) +// bool testNamedCustomDestructor() { +// if (CheckCustomDestructor c = CheckCustomDestructor()) +// return true; +// return false; +// } + + bool testMultipleTemporariesCustomDestructor() { + if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor())) return true; return false; } @@ -477,8 +483,7 @@ namespace NoReturn { void g2(int *x) { if (! x) NR(); - // FIXME: this shouldn't cause a warning. - *x = 47; // expected-warning{{Dereference of null pointer}} + *x = 47; // no warning } }