static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call, const StackFrameContext *calleeCtx) { const Decl *RuntimeCallee = calleeCtx->getDecl(); const Decl *StaticDecl = Call->getDecl(); assert(RuntimeCallee); if (!StaticDecl) return true; return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl(); }
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { 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; } // 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). EvalCallOptions CallOpts; auto C = getCurrentCFGElement().getAs<CFGConstructor>(); assert(C || getCurrentCFGElement().getAs<CFGStmt>()); const ConstructionContext *CC = C ? C->getConstructionContext() : nullptr; switch (CE->getConstructionKind()) { case CXXConstructExpr::CK_Complete: { std::tie(State, Target) = prepareForObjectConstruction(CE, State, LCtx, CC, CallOpts); 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->getStackFrame()->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; } } } LLVM_FALLTHROUGH; case CXXConstructExpr::CK_NonVirtualBase: // In C++17, classes with non-virtual bases may be aggregates, so they would // be initialized as aggregates without a constructor call, so we may have // a base class constructed directly into an initializer list without // having the derived-class constructor call on the previous stack frame. // Initializer lists may be nested into more initializer lists that // correspond to surrounding aggregate initializations. // FIXME: For now this code essentially bails out. We need to find the // correct target region and set it. // 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))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(CE, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; break; } LLVM_FALLTHROUGH; case CXXConstructExpr::CK_Delegating: { const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl()); Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor, LCtx->getStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); if (CE->getConstructionKind() == 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); Target = BaseVal; } break; } } if (State != Pred->getState()) { static SimpleProgramPointTag T("ExprEngine", "Prepare for object construction"); ExplodedNodeSet DstPrepare; StmtNodeBuilder BldrPrepare(Pred, DstPrepare, *currBldrCtx); BldrPrepare.generateNode(CE, Pred, State, &T, ProgramPoint::PreStmtKind); assert(DstPrepare.size() <= 1); if (DstPrepare.size() == 0) return; Pred = *BldrPrepare.begin(); } CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXConstructorCall> Call = CEMgr.getCXXConstructorCall(CE, Target.getAsRegion(), State, LCtx); ExplodedNodeSet DstPreVisit; getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this); // FIXME: Is it possible and/or useful to do this before PreStmt? ExplodedNodeSet PreInitialized; { StmtNodeBuilder Bldr(DstPreVisit, PreInitialized, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), E = DstPreVisit.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); if (CE->requiresZeroInitialization()) { // 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->bindDefaultZero(Target, LCtx); } Bldr.generateNode(CE, *I, State, /*tag=*/nullptr, ProgramPoint::PreStmtKind); } } ExplodedNodeSet DstPreCall; getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized, *Call, *this); ExplodedNodeSet DstEvaluated; StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx); if (CE->getConstructor()->isTrivial() && CE->getConstructor()->isCopyOrMoveConstructor() && !CallOpts.IsArrayCtorOrDtor) { // 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, CallOpts); } // If the CFG was constructed without elements for temporary destructors // and the just-called constructor created a temporary object then // stop exploration if the temporary object has a noreturn constructor. // This can lose coverage because the destructor, if it were present // in the CFG, would be called at the end of the full expression or // later (for life-time extended temporaries) -- but avoids infeasible // 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 we've inlined the constructor, then DstEvaluated would be empty. // In this case we still want a sink, which could be implemented // in processCallExit. But we don't have that implemented at the moment, // so if you hit this assertion, see if you can avoid inlining // the respective constructor when analyzer-config cfg-temporary-dtors // is set to false. // Otherwise there's nothing wrong with inlining such constructor. assert(!DstEvaluated.empty() && "We should not have inlined this constructor!"); for (ExplodedNode *N : DstEvaluated) { Bldr.generateSink(CE, N, N->getState()); } // There is no need to run the PostCall and PostStmt checker // callbacks because we just generated sinks on all nodes in th // frontier. return; } } ExplodedNodeSet DstPostArgumentCleanup; for (auto I : DstEvaluated) finishArgumentConstruction(DstPostArgumentCleanup, I, *Call); // If there were other constructors called for object-type arguments // of this constructor, clean them up. ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(DstPostCall, DstPostArgumentCleanup, *Call, *this); getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this); }
/// The call exit is simulated with a sequence of nodes, which occur between /// CallExitBegin and CallExitEnd. The following operations occur between the /// two program points: /// 1. CallExitBegin (triggers the start of call exit sequence) /// 2. Bind the return value /// 3. Run Remove dead bindings to clean up the dead symbols from the callee. /// 4. CallExitEnd (switch to the caller context) /// 5. PostStmt<CallExpr> void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // Step 1 CEBNode was generated before the call. const StackFrameContext *calleeCtx = CEBNode->getLocationContext()->getCurrentStackFrame(); // The parent context might not be a stack frame, so make sure we // look up the first enclosing stack frame. const StackFrameContext *callerCtx = calleeCtx->getParent()->getCurrentStackFrame(); const Stmt *CE = calleeCtx->getCallSite(); ProgramStateRef state = CEBNode->getState(); // Find the last statement in the function and the corresponding basic block. const Stmt *LastSt = 0; const CFGBlock *Blk = 0; llvm::tie(LastSt, Blk) = getLastStmt(CEBNode); // Generate a CallEvent /before/ cleaning the state, so that we can get the // correct value for 'this' (if necessary). CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state); // Step 2: generate node with bound return value: CEBNode -> BindedRetNode. // If the callee returns an expression, bind its value to CallExpr. if (CE) { if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) { const LocationContext *LCtx = CEBNode->getLocationContext(); SVal V = state->getSVal(RS, LCtx); const Decl *Callee = calleeCtx->getDecl(); if (Callee != Call->getDecl()) { QualType ReturnedTy = CallEvent::getDeclaredResultType(Callee); if (!ReturnedTy.isNull()) { if (const Expr *Ex = dyn_cast<Expr>(CE)) { V = adjustReturnValue(V, Ex->getType(), ReturnedTy, getStoreManager()); } } } state = state->BindExpr(CE, callerCtx, V); } // Bind the constructed object value to CXXConstructExpr. if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) { loc::MemRegionVal This = svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx); SVal ThisV = state->getSVal(This); // If the constructed object is a prvalue, get its bindings. // Note that we have to be careful here because constructors embedded // in DeclStmts are not marked as lvalues. if (!CCE->isGLValue()) if (const MemRegion *MR = ThisV.getAsRegion()) if (isa<CXXTempObjectRegion>(MR)) ThisV = state->getSVal(cast<Loc>(ThisV)); state = state->BindExpr(CCE, callerCtx, ThisV); } } // Step 3: BindedRetNode -> CleanedNodes // If we can find a statement and a block in the inlined function, run remove // dead bindings before returning from the call. This is important to ensure // that we report the issues such as leaks in the stack contexts in which // they occurred. ExplodedNodeSet CleanedNodes; if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) { static SimpleProgramPointTag retValBind("ExprEngine : Bind Return Value"); PostStmt Loc(LastSt, calleeCtx, &retValBind); bool isNew; ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew); BindedRetNode->addPredecessor(CEBNode, G); if (!isNew) return; NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode); currBldrCtx = &Ctx; // Here, we call the Symbol Reaper with 0 statement and caller location // context, telling it to clean up everything in the callee's context // (and it's children). We use LastStmt as a diagnostic statement, which // which the PreStmtPurge Dead point will be associated. removeDead(BindedRetNode, CleanedNodes, 0, callerCtx, LastSt, ProgramPoint::PostStmtPurgeDeadSymbolsKind); currBldrCtx = 0; } else { CleanedNodes.Add(CEBNode); } for (ExplodedNodeSet::iterator I = CleanedNodes.begin(), E = CleanedNodes.end(); I != E; ++I) { // Step 4: Generate the CallExit and leave the callee's context. // CleanedNodes -> CEENode CallExitEnd Loc(calleeCtx, callerCtx); bool isNew; ProgramStateRef CEEState = (*I == CEBNode) ? state : (*I)->getState(); ExplodedNode *CEENode = G.getNode(Loc, CEEState, false, &isNew); CEENode->addPredecessor(*I, G); if (!isNew) return; // Step 5: Perform the post-condition check of the CallExpr and enqueue the // result onto the work list. // CEENode -> Dst -> WorkList NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode); SaveAndRestore<const NodeBuilderContext*> NBCSave(currBldrCtx, &Ctx); SaveAndRestore<unsigned> CBISave(currStmtIdx, calleeCtx->getIndex()); CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState); ExplodedNodeSet DstPostCall; getCheckerManager().runCheckersForPostCall(DstPostCall, CEENode, *UpdatedCall, *this, /*WasInlined=*/true); ExplodedNodeSet Dst; if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) { getCheckerManager().runCheckersForPostObjCMessage(Dst, DstPostCall, *Msg, *this, /*WasInlined=*/true); } else if (CE) { getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE, *this, /*WasInlined=*/true); } else { Dst.insert(DstPostCall); } // Enqueue the next element in the block. for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end(); PSI != PSE; ++PSI) { Engine.getWorkList()->enqueue(*PSI, calleeCtx->getCallSiteBlock(), calleeCtx->getIndex()+1); } } }