diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index ffc382fcf077..5746bfb7248e 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -171,18 +171,28 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, const Expr *Ex, const Expr *Result) { SVal V = State->getSVal(Ex, LC); - if (!Result && !V.getAs()) - return State; + if (!Result) { + // If we don't have an explicit result expression, we're in "if needed" + // mode. Only create a region if the current value is a NonLoc. + if (!V.getAs()) + return State; + Result = Ex; + } else { + // We need to create a region no matter what. For sanity, make sure we don't + // try to stuff a Loc into a non-pointer temporary region. + assert(!V.getAs() || Loc::isLocType(Result->getType())); + } 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. + // bindings for a base type. Unless we're creating a temporary pointer region, + // start by stripping and recording base casts. SmallVector Casts; const Expr *Inner = Ex->IgnoreParens(); - if (V.getAs()) { + if (!Loc::isLocType(Result->getType())) { while (const CastExpr *CE = dyn_cast(Inner)) { if (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_UncheckedDerivedToBase) @@ -195,8 +205,13 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, } // 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)); + // a more derived type) and bind the value into it. + const TypedValueRegion *TR = MRMgr.getCXXTempObjectRegion(Inner, LC); + SVal Reg = loc::MemRegionVal(TR); + + if (V.isUnknown()) + V = getSValBuilder().conjureSymbolVal(Result, LC, TR->getValueType(), + currBldrCtx->blockCount()); State = State->bindLoc(Reg, V); // Re-apply the casts (from innermost to outermost) for type sanity. @@ -206,7 +221,7 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, Reg = StoreMgr.evalDerivedToBase(Reg, *I); } - State = State->BindExpr(Result ? Result : Ex, LC, Reg); + State = State->BindExpr(Result, LC, Reg); return State; } @@ -515,18 +530,20 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - ProgramStateRef state = Pred->getState(); const VarDecl *varDecl = Dtor.getVarDecl(); - QualType varType = varDecl->getType(); - if (const ReferenceType *refType = varType->getAs()) + ProgramStateRef state = Pred->getState(); + SVal dest = state->getLValue(varDecl, Pred->getLocationContext()); + const MemRegion *Region = dest.castAs().getRegion(); + + if (const ReferenceType *refType = varType->getAs()) { varType = refType->getPointeeType(); + Region = state->getSVal(Region).getAsRegion(); + } - Loc dest = state->getLValue(varDecl, Pred->getLocationContext()); - - VisitCXXDestructor(varType, dest.castAs().getRegion(), - Dtor.getTriggerStmt(), /*IsBase=*/ false, Pred, Dst); + VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), /*IsBase=*/ false, + Pred, Dst); } void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, diff --git a/clang/test/Analysis/dtor.cpp b/clang/test/Analysis/dtor.cpp index a30823766e79..18cd9853f661 100644 --- a/clang/test/Analysis/dtor.cpp +++ b/clang/test/Analysis/dtor.cpp @@ -328,3 +328,76 @@ namespace MultidimensionalArrays { clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}} } } + +namespace LifetimeExtension { + struct IntWrapper { + int x; + IntWrapper(int y) : x(y) {} + IntWrapper() { + extern void use(int); + use(x); // no-warning + } + }; + + struct DerivedWrapper : public IntWrapper { + DerivedWrapper(int y) : IntWrapper(y) {} + }; + + DerivedWrapper get() { + return DerivedWrapper(1); + } + + void test() { + const DerivedWrapper &d = get(); // lifetime extended here + } + + + class SaveOnDestruct { + public: + static int lastOutput; + int value; + + SaveOnDestruct(); + ~SaveOnDestruct() { + lastOutput = value; + } + }; + + void testSimple() { + { + const SaveOnDestruct &obj = SaveOnDestruct(); + if (obj.value != 42) + return; + // destructor called here + } + + clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}} + } + + class VirtualDtorBase { + public: + int value; + virtual ~VirtualDtorBase() {} + }; + + class SaveOnVirtualDestruct : public VirtualDtorBase { + public: + static int lastOutput; + + SaveOnVirtualDestruct(); + virtual ~SaveOnVirtualDestruct() { + lastOutput = value; + } + }; + + void testVirtual() { + { + const VirtualDtorBase &obj = SaveOnVirtualDestruct(); + if (obj.value != 42) + return; + // destructor called here + } + + clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}} + } +}