aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-02-21 23:57:17 +0000
committerJordan Rose <jordan_rose@apple.com>2013-02-21 23:57:17 +0000
commit9f1d541ef1aca8f953e5bb4e7177969f0a2062d5 (patch)
treee0054aa29b2c5dff3f6ed9d98f5cd1065439f102
parent3892d022f36ee5bf3be4a55ea01c08d323ef6235 (diff)
[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> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175830 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp35
-rw-r--r--test/Analysis/temporaries.cpp26
2 files changed, 57 insertions, 4 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 06b1db564d..60fd8d019e 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -173,10 +173,37 @@ static ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
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;
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index e885878783..8d0dd6e04c 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -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}}
+ }
+}
+