void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef State = Pred->getState(); const MemRegion *Target = nullptr; // FIXME: Handle arrays, which run the same constructor for every element. // For now, we just run the first constructor (which should still invalidate // the entire array). switch (CE->getConstructionKind()) { case CXXConstructExpr::CK_Complete: { Target = getRegionForConstructedObject(CE, Pred, *this, currStmtIdx); break; } case CXXConstructExpr::CK_VirtualBase: // Make sure we are not calling virtual base class initializers twice. // Only the most-derived object should initialize virtual base classes. if (const Stmt *Outer = LCtx->getCurrentStackFrame()->getCallSite()) { const CXXConstructExpr *OuterCtor = dyn_cast<CXXConstructExpr>(Outer); if (OuterCtor) { switch (OuterCtor->getConstructionKind()) { case CXXConstructExpr::CK_NonVirtualBase: case CXXConstructExpr::CK_VirtualBase: // Bail out! destNodes.Add(Pred); return; case CXXConstructExpr::CK_Complete: case CXXConstructExpr::CK_Delegating: break; } } } // FALLTHROUGH case CXXConstructExpr::CK_NonVirtualBase: case CXXConstructExpr::CK_Delegating: { const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor, LCtx->getCurrentStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); if (CE->getConstructionKind() == CXXConstructExpr::CK_Delegating) { Target = ThisVal.getAsRegion(); } else { // Cast to the base type. bool IsVirtual = (CE->getConstructionKind() == CXXConstructExpr::CK_VirtualBase); SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, CE->getType(), IsVirtual); Target = BaseVal.getAsRegion(); } break; } } CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXConstructorCall> Call = CEMgr.getCXXConstructorCall(CE, Target, State, LCtx); ExplodedNodeSet DstPreVisit; getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this); ExplodedNodeSet PreInitialized; { StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx); if (CE->requiresZeroInitialization()) { // Type of the zero doesn't matter. SVal ZeroVal = svalBuilder.makeZeroVal(getContext().CharTy); for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), E = DstPreVisit.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); // FIXME: Once we properly handle constructors in new-expressions, we'll // need to invalidate the region before setting a default value, to make // sure there aren't any lingering bindings around. This probably needs // to happen regardless of whether or not the object is zero-initialized // to handle random fields of a placement-initialized object picking up // old bindings. We might only want to do it when we need to, though. // FIXME: This isn't actually correct for arrays -- we need to zero- // initialize the entire array, not just the first element -- but our // handling of arrays everywhere else is weak as well, so this shouldn't // actually make things worse. Placement new makes this tricky as well, // since it's then possible to be initializing one part of a multi- // dimensional array. State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal); Bldr.generateNode(CE, *I, State, /*tag=*/nullptr, ProgramPoint::PreStmtKind); } } } ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized, *Call, *this); ExplodedNodeSet DstEvaluated; StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx); bool IsArray = isa<ElementRegion>(Target); if (CE->getConstructor()->isTrivial() && CE->getConstructor()->isCopyOrMoveConstructor() && !IsArray) { // FIXME: Handle other kinds of trivial constructors as well. for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) performTrivialCopy(Bldr, *I, *Call); } else { for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(Bldr, *I, *Call); } ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(DstPostCall, DstEvaluated, *Call, *this); getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this); }