diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 354 |
1 files changed, 219 insertions, 135 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index b816aab7c18f8..38a680eb04c00 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -109,15 +109,14 @@ SVal ExprEngine::makeZeroElementRegion(ProgramStateRef State, SVal LValue, return LValue; } -std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( +SVal ExprEngine::computeObjectUnderConstruction( const Expr *E, ProgramStateRef State, const LocationContext *LCtx, const ConstructionContext *CC, EvalCallOptions &CallOpts) { SValBuilder &SVB = getSValBuilder(); MemRegionManager &MRMgr = SVB.getRegionManager(); ASTContext &ACtx = SVB.getContext(); - // See if we're constructing an existing region by looking at the - // current construction context. + // Compute the target region by exploring the construction context. if (CC) { switch (CC->getKind()) { case ConstructionContext::CXX17ElidedCopyVariableKind: @@ -125,13 +124,9 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( const auto *DSCC = cast<VariableConstructionContext>(CC); const auto *DS = DSCC->getDeclStmt(); const auto *Var = cast<VarDecl>(DS->getSingleDecl()); - SVal LValue = State->getLValue(Var, LCtx); QualType Ty = Var->getType(); - LValue = - makeZeroElementRegion(State, LValue, Ty, CallOpts.IsArrayCtorOrDtor); - State = - addObjectUnderConstruction(State, DSCC->getDeclStmt(), LCtx, LValue); - return std::make_pair(State, LValue); + return makeZeroElementRegion(State, State->getLValue(Var, LCtx), Ty, + CallOpts.IsArrayCtorOrDtor); } case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind: case ConstructionContext::SimpleConstructorInitializerKind: { @@ -139,8 +134,7 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( const auto *Init = ICC->getCXXCtorInitializer(); assert(Init->isAnyMemberInitializer()); const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); - Loc ThisPtr = - SVB.getCXXThis(CurCtor, LCtx->getStackFrame()); + Loc ThisPtr = SVB.getCXXThis(CurCtor, LCtx->getStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); const ValueDecl *Field; @@ -154,10 +148,8 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( } QualType Ty = Field->getType(); - FieldVal = makeZeroElementRegion(State, FieldVal, Ty, - CallOpts.IsArrayCtorOrDtor); - State = addObjectUnderConstruction(State, Init, LCtx, FieldVal); - return std::make_pair(State, FieldVal); + return makeZeroElementRegion(State, FieldVal, Ty, + CallOpts.IsArrayCtorOrDtor); } case ConstructionContext::NewAllocatedObjectKind: { if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) { @@ -170,11 +162,10 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( // TODO: In fact, we need to call the constructor for every // allocated element, not just the first one! CallOpts.IsArrayCtorOrDtor = true; - return std::make_pair( - State, loc::MemRegionVal(getStoreManager().GetElementZeroRegion( - MR, NE->getType()->getPointeeType()))); + return loc::MemRegionVal(getStoreManager().GetElementZeroRegion( + MR, NE->getType()->getPointeeType())); } - return std::make_pair(State, V); + return V; } // TODO: Detect when the allocator returns a null pointer. // Constructor shall not be called in this case. @@ -202,7 +193,7 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( CallerLCtx = CallerLCtx->getParent(); assert(!isa<BlockInvocationContext>(CallerLCtx)); } - return prepareForObjectConstruction( + return computeObjectUnderConstruction( cast<Expr>(SFC->getCallSite()), State, CallerLCtx, RTC->getConstructionContext(), CallOpts); } else { @@ -223,64 +214,46 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( assert(RetE && "Void returns should not have a construction context"); QualType ReturnTy = RetE->getType(); QualType RegionTy = ACtx.getPointerType(ReturnTy); - SVal V = SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC, - RegionTy, currBldrCtx->blockCount()); - return std::make_pair(State, V); + return SVB.conjureSymbolVal(&TopLevelSymRegionTag, RetE, SFC, RegionTy, + currBldrCtx->blockCount()); } llvm_unreachable("Unhandled return value construction context!"); } case ConstructionContext::ElidedTemporaryObjectKind: { assert(AMgr.getAnalyzerOptions().ShouldElideConstructors); const auto *TCC = cast<ElidedTemporaryObjectConstructionContext>(CC); - const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr(); - const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr(); - const CXXConstructExpr *CE = TCC->getConstructorAfterElision(); // Support pre-C++17 copy elision. We'll have the elidable copy // constructor in the AST and in the CFG, but we'll skip it // and construct directly into the final object. This call // also sets the CallOpts flags for us. - SVal V; // If the elided copy/move constructor is not supported, there's still // benefit in trying to model the non-elided constructor. // Stash our state before trying to elide, as it'll get overwritten. ProgramStateRef PreElideState = State; EvalCallOptions PreElideCallOpts = CallOpts; - std::tie(State, V) = prepareForObjectConstruction( - CE, State, LCtx, TCC->getConstructionContextAfterElision(), CallOpts); + SVal V = computeObjectUnderConstruction( + TCC->getConstructorAfterElision(), State, LCtx, + TCC->getConstructionContextAfterElision(), CallOpts); // FIXME: This definition of "copy elision has not failed" is unreliable. // It doesn't indicate that the constructor will actually be inlined - // later; it is still up to evalCall() to decide. - if (!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) { - // Remember that we've elided the constructor. - State = addObjectUnderConstruction(State, CE, LCtx, V); - - // Remember that we've elided the destructor. - if (BTE) - State = elideDestructor(State, BTE, LCtx); - - // Instead of materialization, shamelessly return - // the final object destination. - if (MTE) - State = addObjectUnderConstruction(State, MTE, LCtx, V); - - return std::make_pair(State, V); - } else { - // Copy elision failed. Revert the changes and proceed as if we have - // a simple temporary. - State = PreElideState; - CallOpts = PreElideCallOpts; - } + // later; this is still up to evalCall() to decide. + if (!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) + return V; + + // Copy elision failed. Revert the changes and proceed as if we have + // a simple temporary. + CallOpts = PreElideCallOpts; + CallOpts.IsElidableCtorThatHasNotBeenElided = true; LLVM_FALLTHROUGH; } case ConstructionContext::SimpleTemporaryObjectKind: { const auto *TCC = cast<TemporaryObjectConstructionContext>(CC); - const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr(); const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr(); - SVal V = UnknownVal(); + CallOpts.IsTemporaryCtorOrDtor = true; if (MTE) { if (const ValueDecl *VD = MTE->getExtendingDecl()) { assert(MTE->getStorageDuration() != SD_FullExpression); @@ -296,20 +269,10 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( if (MTE->getStorageDuration() == SD_Static || MTE->getStorageDuration() == SD_Thread) - V = loc::MemRegionVal(MRMgr.getCXXStaticTempObjectRegion(E)); + return loc::MemRegionVal(MRMgr.getCXXStaticTempObjectRegion(E)); } - if (V.isUnknown()) - V = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); - - if (BTE) - State = addObjectUnderConstruction(State, BTE, LCtx, V); - - if (MTE) - State = addObjectUnderConstruction(State, MTE, LCtx, V); - - CallOpts.IsTemporaryCtorOrDtor = true; - return std::make_pair(State, V); + return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); } case ConstructionContext::ArgumentKind: { // Arguments are technically temporaries. @@ -318,10 +281,8 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( const auto *ACC = cast<ArgumentConstructionContext>(CC); const Expr *E = ACC->getCallLikeExpr(); unsigned Idx = ACC->getIndex(); - const CXXBindTemporaryExpr *BTE = ACC->getCXXBindTemporaryExpr(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); - SVal V = UnknownVal(); auto getArgLoc = [&](CallEventRef<> Caller) -> Optional<SVal> { const LocationContext *FutureSFC = Caller->getCalleeStackFrame(currBldrCtx->blockCount()); @@ -342,76 +303,171 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction( // Operator arguments do not correspond to operator parameters // because this-argument is implemented as a normal argument in // operator call expressions but not in operator declarations. - const VarRegion *VR = Caller->getParameterLocation( + const TypedValueRegion *TVR = Caller->getParameterLocation( *Caller->getAdjustedParameterIndex(Idx), currBldrCtx->blockCount()); - if (!VR) + if (!TVR) return None; - return loc::MemRegionVal(VR); + return loc::MemRegionVal(TVR); }; if (const auto *CE = dyn_cast<CallExpr>(E)) { CallEventRef<> Caller = CEMgr.getSimpleCall(CE, State, LCtx); - if (auto OptV = getArgLoc(Caller)) - V = *OptV; + if (Optional<SVal> V = getArgLoc(Caller)) + return *V; else break; - State = addObjectUnderConstruction(State, {CE, Idx}, LCtx, V); } else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) { // Don't bother figuring out the target region for the future // constructor because we won't need it. CallEventRef<> Caller = CEMgr.getCXXConstructorCall(CCE, /*Target=*/nullptr, State, LCtx); - if (auto OptV = getArgLoc(Caller)) - V = *OptV; + if (Optional<SVal> V = getArgLoc(Caller)) + return *V; else break; - State = addObjectUnderConstruction(State, {CCE, Idx}, LCtx, V); } else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) { CallEventRef<> Caller = CEMgr.getObjCMethodCall(ME, State, LCtx); - if (auto OptV = getArgLoc(Caller)) - V = *OptV; + if (Optional<SVal> V = getArgLoc(Caller)) + return *V; else break; - State = addObjectUnderConstruction(State, {ME, Idx}, LCtx, V); + } + } + } // switch (CC->getKind()) + } + + // If we couldn't find an existing region to construct into, assume we're + // constructing a temporary. Notify the caller of our failure. + CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; + return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); +} + +ProgramStateRef ExprEngine::updateObjectsUnderConstruction( + SVal V, const Expr *E, ProgramStateRef State, const LocationContext *LCtx, + const ConstructionContext *CC, const EvalCallOptions &CallOpts) { + if (CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) { + // Sounds like we failed to find the target region and therefore + // copy elision failed. There's nothing we can do about it here. + return State; + } + + // See if we're constructing an existing region by looking at the + // current construction context. + assert(CC && "Computed target region without construction context?"); + switch (CC->getKind()) { + case ConstructionContext::CXX17ElidedCopyVariableKind: + case ConstructionContext::SimpleVariableKind: { + const auto *DSCC = cast<VariableConstructionContext>(CC); + return addObjectUnderConstruction(State, DSCC->getDeclStmt(), LCtx, V); + } + case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind: + case ConstructionContext::SimpleConstructorInitializerKind: { + const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC); + return addObjectUnderConstruction(State, ICC->getCXXCtorInitializer(), + LCtx, V); + } + case ConstructionContext::NewAllocatedObjectKind: { + return State; + } + case ConstructionContext::SimpleReturnedValueKind: + case ConstructionContext::CXX17ElidedCopyReturnedValueKind: { + const StackFrameContext *SFC = LCtx->getStackFrame(); + const LocationContext *CallerLCtx = SFC->getParent(); + if (!CallerLCtx) { + // No extra work is necessary in top frame. + return State; } - assert(!V.isUnknown()); + auto RTC = (*SFC->getCallSiteBlock())[SFC->getIndex()] + .getAs<CFGCXXRecordTypedCall>(); + assert(RTC && "Could not have had a target region without it"); + if (isa<BlockInvocationContext>(CallerLCtx)) { + // Unwrap block invocation contexts. They're mostly part of + // the current stack frame. + CallerLCtx = CallerLCtx->getParent(); + assert(!isa<BlockInvocationContext>(CallerLCtx)); + } - if (BTE) + return updateObjectsUnderConstruction(V, + cast<Expr>(SFC->getCallSite()), State, CallerLCtx, + RTC->getConstructionContext(), CallOpts); + } + case ConstructionContext::ElidedTemporaryObjectKind: { + assert(AMgr.getAnalyzerOptions().ShouldElideConstructors); + if (!CallOpts.IsElidableCtorThatHasNotBeenElided) { + const auto *TCC = cast<ElidedTemporaryObjectConstructionContext>(CC); + State = updateObjectsUnderConstruction( + V, TCC->getConstructorAfterElision(), State, LCtx, + TCC->getConstructionContextAfterElision(), CallOpts); + + // Remember that we've elided the constructor. + State = addObjectUnderConstruction( + State, TCC->getConstructorAfterElision(), LCtx, V); + + // Remember that we've elided the destructor. + if (const auto *BTE = TCC->getCXXBindTemporaryExpr()) + State = elideDestructor(State, BTE, LCtx); + + // Instead of materialization, shamelessly return + // the final object destination. + if (const auto *MTE = TCC->getMaterializedTemporaryExpr()) + State = addObjectUnderConstruction(State, MTE, LCtx, V); + + return State; + } + // If we decided not to elide the constructor, proceed as if + // it's a simple temporary. + LLVM_FALLTHROUGH; + } + case ConstructionContext::SimpleTemporaryObjectKind: { + const auto *TCC = cast<TemporaryObjectConstructionContext>(CC); + if (const auto *BTE = TCC->getCXXBindTemporaryExpr()) State = addObjectUnderConstruction(State, BTE, LCtx, V); - return std::make_pair(State, V); + if (const auto *MTE = TCC->getMaterializedTemporaryExpr()) + State = addObjectUnderConstruction(State, MTE, LCtx, V); + + return State; } + case ConstructionContext::ArgumentKind: { + const auto *ACC = cast<ArgumentConstructionContext>(CC); + if (const auto *BTE = ACC->getCXXBindTemporaryExpr()) + State = addObjectUnderConstruction(State, BTE, LCtx, V); + + return addObjectUnderConstruction( + State, {ACC->getCallLikeExpr(), ACC->getIndex()}, LCtx, V); } } - // If we couldn't find an existing region to construct into, assume we're - // constructing a temporary. Notify the caller of our failure. - CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; - return std::make_pair( - State, loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx))); + llvm_unreachable("Unhandled construction context!"); } -void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, - ExplodedNode *Pred, - ExplodedNodeSet &destNodes) { +void ExprEngine::handleConstructor(const Expr *E, + ExplodedNode *Pred, + ExplodedNodeSet &destNodes) { + const auto *CE = dyn_cast<CXXConstructExpr>(E); + const auto *CIE = dyn_cast<CXXInheritedCtorInitExpr>(E); + assert(CE || CIE); + const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); SVal Target = UnknownVal(); - if (Optional<SVal> ElidedTarget = - getObjectUnderConstruction(State, CE, LCtx)) { - // We've previously modeled an elidable constructor by pretending that it in - // fact constructs into the correct target. This constructor can therefore - // be skipped. - Target = *ElidedTarget; - StmtNodeBuilder Bldr(Pred, destNodes, *currBldrCtx); - State = finishObjectConstruction(State, CE, LCtx); - if (auto L = Target.getAs<Loc>()) - State = State->BindExpr(CE, LCtx, State->getSVal(*L, CE->getType())); - Bldr.generateNode(CE, Pred, State); - return; + if (CE) { + if (Optional<SVal> ElidedTarget = + getObjectUnderConstruction(State, CE, LCtx)) { + // We've previously modeled an elidable constructor by pretending that it + // in fact constructs into the correct target. This constructor can + // therefore be skipped. + Target = *ElidedTarget; + StmtNodeBuilder Bldr(Pred, destNodes, *currBldrCtx); + State = finishObjectConstruction(State, CE, LCtx); + if (auto L = Target.getAs<Loc>()) + State = State->BindExpr(CE, LCtx, State->getSVal(*L, CE->getType())); + Bldr.generateNode(CE, Pred, State); + return; + } } // FIXME: Handle arrays, which run the same constructor for every element. @@ -423,10 +479,16 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, assert(C || getCurrentCFGElement().getAs<CFGStmt>()); const ConstructionContext *CC = C ? C->getConstructionContext() : nullptr; - switch (CE->getConstructionKind()) { + const CXXConstructExpr::ConstructionKind CK = + CE ? CE->getConstructionKind() : CIE->getConstructionKind(); + switch (CK) { case CXXConstructExpr::CK_Complete: { + // Inherited constructors are always base class constructors. + assert(CE && !CIE && "A complete constructor is inherited?!"); + + // The target region is found from construction context. std::tie(State, Target) = - prepareForObjectConstruction(CE, State, LCtx, CC, CallOpts); + handleConstructionContext(CE, State, LCtx, CC, CallOpts); break; } case CXXConstructExpr::CK_VirtualBase: { @@ -455,9 +517,9 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, // FIXME: Instead of relying on the ParentMap, we should have the // trigger-statement (InitListExpr in this case) passed down from CFG or // otherwise always available during construction. - if (dyn_cast_or_null<InitListExpr>(LCtx->getParentMap().getParent(CE))) { + if (dyn_cast_or_null<InitListExpr>(LCtx->getParentMap().getParent(E))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); - Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(CE, LCtx)); + Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; break; } @@ -468,14 +530,13 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, LCtx->getStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); - if (CE->getConstructionKind() == CXXConstructExpr::CK_Delegating) { + if (CK == CXXConstructExpr::CK_Delegating) { Target = ThisVal; } else { // Cast to the base type. - bool IsVirtual = - (CE->getConstructionKind() == CXXConstructExpr::CK_VirtualBase); - SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, CE->getType(), - IsVirtual); + bool IsVirtual = (CK == CXXConstructExpr::CK_VirtualBase); + SVal BaseVal = + getStoreManager().evalDerivedToBase(ThisVal, E->getType(), IsVirtual); Target = BaseVal; } break; @@ -487,23 +548,27 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, "Prepare for object construction"); ExplodedNodeSet DstPrepare; StmtNodeBuilder BldrPrepare(Pred, DstPrepare, *currBldrCtx); - BldrPrepare.generateNode(CE, Pred, State, &T, ProgramPoint::PreStmtKind); + BldrPrepare.generateNode(E, Pred, State, &T, ProgramPoint::PreStmtKind); assert(DstPrepare.size() <= 1); if (DstPrepare.size() == 0) return; Pred = *BldrPrepare.begin(); } + const MemRegion *TargetRegion = Target.getAsRegion(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); - CallEventRef<CXXConstructorCall> Call = - CEMgr.getCXXConstructorCall(CE, Target.getAsRegion(), State, LCtx); + CallEventRef<> Call = + CIE ? (CallEventRef<>)CEMgr.getCXXInheritedConstructorCall( + CIE, TargetRegion, State, LCtx) + : (CallEventRef<>)CEMgr.getCXXConstructorCall( + CE, TargetRegion, State, LCtx); ExplodedNodeSet DstPreVisit; - getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this); + getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, E, *this); - // FIXME: Is it possible and/or useful to do this before PreStmt? ExplodedNodeSet PreInitialized; - { + if (CE) { + // FIXME: Is it possible and/or useful to do this before PreStmt? StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), E = DstPreVisit.end(); @@ -528,6 +593,8 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, Bldr.generateNode(CE, *I, State, /*tag=*/nullptr, ProgramPoint::PreStmtKind); } + } else { + PreInitialized = DstPreVisit; } ExplodedNodeSet DstPreCall; @@ -537,7 +604,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNodeSet DstEvaluated; StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx); - if (CE->getConstructor()->isTrivial() && + if (CE && CE->getConstructor()->isTrivial() && CE->getConstructor()->isCopyOrMoveConstructor() && !CallOpts.IsArrayCtorOrDtor) { // FIXME: Handle other kinds of trivial constructors as well. @@ -548,7 +615,8 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, } else { for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) - defaultEvalCall(Bldr, *I, *Call, CallOpts); + getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, *this, + CallOpts); } // If the CFG was constructed without elements for temporary destructors @@ -560,9 +628,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, // paths when no-return temporary destructors are used for assertions. const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext(); if (!ADC->getCFGBuildOptions().AddTemporaryDtors) { - const MemRegion *Target = Call->getCXXThisVal().getAsRegion(); - if (Target && isa<CXXTempObjectRegion>(Target) && - Call->getDecl()->getParent()->isAnyDestructorNoReturn()) { + if (llvm::isa_and_nonnull<CXXTempObjectRegion>(TargetRegion) && + cast<CXXConstructorDecl>(Call->getDecl()) + ->getParent() + ->isAnyDestructorNoReturn()) { // If we've inlined the constructor, then DstEvaluated would be empty. // In this case we still want a sink, which could be implemented @@ -575,7 +644,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, "We should not have inlined this constructor!"); for (ExplodedNode *N : DstEvaluated) { - Bldr.generateSink(CE, N, N->getState()); + Bldr.generateSink(E, N, N->getState()); } // There is no need to run the PostCall and PostStmt checker @@ -586,7 +655,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, } ExplodedNodeSet DstPostArgumentCleanup; - for (auto I : DstEvaluated) + for (ExplodedNode *I : DstEvaluated) finishArgumentConstruction(DstPostArgumentCleanup, I, *Call); // If there were other constructors called for object-type arguments @@ -595,7 +664,19 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, getCheckerManager().runCheckersForPostCall(DstPostCall, DstPostArgumentCleanup, *Call, *this); - getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this); + getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, E, *this); +} + +void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + handleConstructor(CE, Pred, Dst); +} + +void ExprEngine::VisitCXXInheritedCtorInitExpr( + const CXXInheritedCtorInitExpr *CE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + handleConstructor(CE, Pred, Dst); } void ExprEngine::VisitCXXDestructor(QualType ObjectType, @@ -683,7 +764,7 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, ExplodedNodeSet DstPostCall; StmtNodeBuilder CallBldr(DstPreCall, DstPostCall, *currBldrCtx); - for (auto I : DstPreCall) { + for (ExplodedNode *I : DstPreCall) { // FIXME: Provide evalCall for checkers? defaultEvalCall(CallBldr, I, *Call); } @@ -693,7 +774,7 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, // CXXNewExpr gets processed. ExplodedNodeSet DstPostValue; StmtNodeBuilder ValueBldr(DstPostCall, DstPostValue, *currBldrCtx); - for (auto I : DstPostCall) { + for (ExplodedNode *I : DstPostCall) { // FIXME: Because CNE serves as the "call site" for the allocator (due to // lack of a better expression in the AST), the conjured return value symbol // is going to be of the same type (C++ object pointer type). Technically @@ -727,10 +808,8 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE, ExplodedNodeSet DstPostPostCallCallback; getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback, DstPostValue, *Call, *this); - for (auto I : DstPostPostCallCallback) { - getCheckerManager().runCheckersForNewAllocator( - CNE, *getObjectUnderConstruction(I->getState(), CNE, LCtx), Dst, I, - *this); + for (ExplodedNode *I : DstPostPostCallCallback) { + getCheckerManager().runCheckersForNewAllocator(*Call, Dst, I, *this); } } @@ -846,13 +925,18 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); - ProgramStateRef state = Pred->getState(); - Bldr.generateNode(CDE, Pred, state); + + CallEventManager &CEMgr = getStateManager().getCallEventManager(); + CallEventRef<CXXDeallocatorCall> Call = CEMgr.getCXXDeallocatorCall( + CDE, Pred->getState(), Pred->getLocationContext()); + + ExplodedNodeSet DstPreCall; + getCheckerManager().runCheckersForPreCall(DstPreCall, Pred, *Call, *this); + + getCheckerManager().runCheckersForPostCall(Dst, DstPreCall, *Call, *this); } -void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, - ExplodedNode *Pred, +void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { const VarDecl *VD = CS->getExceptionDecl(); if (!VD) { |