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;
// 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;
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}}
+ }
+}
+