r175830 - [analyzer] Make sure a temporary object region matches its initial bindings.

Jordan Rose jordan_rose at apple.com
Thu Feb 21 15:57:17 PST 2013


Author: jrose
Date: Thu Feb 21 17:57:17 2013
New Revision: 175830

URL: http://llvm.org/viewvc/llvm-project?rev=175830&view=rev
Log:
[analyzer] Make sure a temporary object region matches its initial bindings.

When creating a temporary region (say, when a struct rvalue is used as
the base of a member expr), make sure we account for any derived-to-base
casts. We don't actually record these in the LazyCompoundVal that
represents the rvalue, but we need to make sure that the temporary region
we're creating (a) matches the bindings, and (b) matches its expression.

Most of the time this will do exactly the same thing as before, but it
fixes spurious "garbage value" warnings introduced in r175234 by the use
of lazy bindings to model trivial copy constructors.

<rdar://problem/13265460>

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/test/Analysis/temporaries.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=175830&r1=175829&r2=175830&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Thu Feb 21 17:57:17 2013
@@ -173,10 +173,37 @@ static ProgramStateRef createTemporaryRe
   SVal V = State->getSVal(E, LC);
 
   if (V.getAs<NonLoc>()) {
-    MemRegionManager &MRMgr = State->getStateManager().getRegionManager();
-    const MemRegion *R  = MRMgr.getCXXTempObjectRegion(E, LC);
-    State = State->bindLoc(loc::MemRegionVal(R), V);
-    State = State->BindExpr(E, LC, loc::MemRegionVal(R));
+    ProgramStateManager &StateMgr = State->getStateManager();
+    MemRegionManager &MRMgr = StateMgr.getRegionManager();
+    StoreManager &StoreMgr = StateMgr.getStoreManager();
+
+    // We need to be careful about treating a derived type's value as
+    // bindings for a base type. Start by stripping and recording base casts.
+    SmallVector<const CastExpr *, 4> Casts;
+    const Expr *Inner = E->IgnoreParens();
+    while (const CastExpr *CE = dyn_cast<CastExpr>(Inner)) {
+      if (CE->getCastKind() == CK_DerivedToBase ||
+          CE->getCastKind() == CK_UncheckedDerivedToBase)
+        Casts.push_back(CE);
+      else if (CE->getCastKind() != CK_NoOp)
+        break;
+
+      Inner = CE->getSubExpr()->IgnoreParens();
+    }
+
+    // Create a temporary object region for the inner expression (which may have
+    // a more derived type) and bind the NonLoc value into it.
+    SVal Reg = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(Inner, LC));
+    State = State->bindLoc(Reg, V);
+
+    // Re-apply the casts (from innermost to outermost) for type sanity.
+    for (SmallVectorImpl<const CastExpr *>::reverse_iterator I = Casts.rbegin(),
+                                                             E = Casts.rend();
+         I != E; ++I) {
+      Reg = StoreMgr.evalDerivedToBase(Reg, *I);
+    }
+
+    State = State->BindExpr(E, LC, Reg);
   }
 
   return State;

Modified: cfe/trunk/test/Analysis/temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temporaries.cpp?rev=175830&r1=175829&r2=175830&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/temporaries.cpp (original)
+++ cfe/trunk/test/Analysis/temporaries.cpp Thu Feb 21 17:57:17 2013
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w %s
 
+extern bool clang_analyzer_eval(bool);
+
 struct Trivial {
   Trivial(int x) : value(x) {}
   int value;
@@ -28,3 +30,27 @@ const NonTrivial &getNonTrivialRef() {
   return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'const struct NonTrivial' returned to caller}}
 }
 
+namespace rdar13265460 {
+  struct TrivialSubclass : public Trivial {
+    TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {}
+    int anotherValue;
+  };
+
+  TrivialSubclass getTrivialSub() {
+    TrivialSubclass obj(1);
+    obj.value = 42;
+    obj.anotherValue = -42;
+    return obj;
+  }
+
+  void test() {
+    TrivialSubclass obj = getTrivialSub();
+
+    clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}}
+    clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}}
+
+    clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}}
+    clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}}
+  }
+}
+





More information about the cfe-commits mailing list