Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -123,15 +123,18 @@ SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType, bool IsVirtual); - /// \brief Evaluates C++ dynamic_cast cast. + /// \brief Attempts to do a down cast. Used to model BaseToDerived and C++ + /// dynamic_cast. /// The callback may result in the following 3 scenarios: /// - Successful cast (ex: derived is subclass of base). /// - Failed cast (ex: derived is definitely not a subclass of base). + /// The distinction of this case from the next one is necessary to model + /// dynamic_cast. /// - We don't know (base is a symbolic region and we don't have /// enough info to determine if the cast will succeed at run time). /// The function returns an SVal representing the derived class; it's /// valid only if Failed flag is set to false. - SVal evalDynamicCast(SVal Base, QualType DerivedPtrType, bool &Failed); + SVal attemptDownCast(SVal Base, QualType DerivedPtrType, bool &Failed); const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); Index: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -552,7 +552,7 @@ // FIXME: CallEvent maybe shouldn't be directly accessing StoreManager. bool Failed; - ThisVal = StateMgr.getStoreManager().evalDynamicCast(ThisVal, Ty, Failed); + ThisVal = StateMgr.getStoreManager().attemptDownCast(ThisVal, Ty, Failed); assert(!Failed && "Calling an incorrectly devirtualized method"); } Index: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -386,7 +386,7 @@ Failed = true; // Else, evaluate the cast. else - val = getStoreManager().evalDynamicCast(val, T, Failed); + val = getStoreManager().attemptDownCast(val, T, Failed); if (Failed) { if (T->isReferenceType()) { @@ -412,6 +412,28 @@ Bldr.generateNode(CastE, Pred, state); continue; } + case CK_BaseToDerived: { + SVal val = state->getSVal(Ex, LCtx); + QualType resultType = CastE->getType(); + if (CastE->isGLValue()) + resultType = getContext().getPointerType(resultType); + + bool Failed = false; + + if (!val.isConstant()) { + val = getStoreManager().attemptDownCast(val, T, Failed); + } + + // Failed to cast or the result is unknown, fall back to conservative. + if (Failed || val.isUnknown()) { + val = + svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, + currBldrCtx->blockCount()); + } + state = state->BindExpr(CastE, LCtx, val); + Bldr.generateNode(CastE, Pred, state); + continue; + } case CK_NullToMemberPointer: { // FIXME: For now, member pointers are represented by void *. SVal V = svalBuilder.makeNull(); @@ -421,7 +443,6 @@ } // Various C++ casts that are not handled yet. case CK_ToUnion: - case CK_BaseToDerived: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_ReinterpretMemberPointer: Index: cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/Store.cpp @@ -292,7 +292,7 @@ return nullptr; } -SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType, +SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType, bool &Failed) { Failed = false; Index: cfe/trunk/test/Analysis/NewDelete-checker-test.cpp =================================================================== --- cfe/trunk/test/Analysis/NewDelete-checker-test.cpp +++ cfe/trunk/test/Analysis/NewDelete-checker-test.cpp @@ -377,3 +377,19 @@ delete foo; delete foo; // expected-warning {{Attempt to delete released memory}} } + +struct Base { + virtual ~Base() {} +}; + +struct Derived : Base { +}; + +Base *allocate() { + return new Derived; +} + +void shouldNotReportLeak() { + Derived *p = (Derived *)allocate(); + delete p; +}