106f32e7eSjoerg //=-- ExprEngineCallAndReturn.cpp - Support for call/return -----*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This file defines ExprEngine's support for calls and returns.
1006f32e7eSjoerg //
1106f32e7eSjoerg //===----------------------------------------------------------------------===//
1206f32e7eSjoerg
1306f32e7eSjoerg #include "PrettyStackTraceLocationContext.h"
1406f32e7eSjoerg #include "clang/AST/CXXInheritance.h"
15*13fbcb42Sjoerg #include "clang/AST/Decl.h"
1606f32e7eSjoerg #include "clang/AST/DeclCXX.h"
1706f32e7eSjoerg #include "clang/Analysis/Analyses/LiveVariables.h"
1806f32e7eSjoerg #include "clang/Analysis/ConstructionContext.h"
1906f32e7eSjoerg #include "clang/StaticAnalyzer/Core/CheckerManager.h"
2006f32e7eSjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
21*13fbcb42Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
22*13fbcb42Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
2306f32e7eSjoerg #include "llvm/ADT/SmallSet.h"
2406f32e7eSjoerg #include "llvm/ADT/Statistic.h"
25*13fbcb42Sjoerg #include "llvm/Support/Casting.h"
26*13fbcb42Sjoerg #include "llvm/Support/Compiler.h"
2706f32e7eSjoerg #include "llvm/Support/SaveAndRestore.h"
2806f32e7eSjoerg
2906f32e7eSjoerg using namespace clang;
3006f32e7eSjoerg using namespace ento;
3106f32e7eSjoerg
3206f32e7eSjoerg #define DEBUG_TYPE "ExprEngine"
3306f32e7eSjoerg
3406f32e7eSjoerg STATISTIC(NumOfDynamicDispatchPathSplits,
3506f32e7eSjoerg "The # of times we split the path due to imprecise dynamic dispatch info");
3606f32e7eSjoerg
3706f32e7eSjoerg STATISTIC(NumInlinedCalls,
3806f32e7eSjoerg "The # of times we inlined a call");
3906f32e7eSjoerg
4006f32e7eSjoerg STATISTIC(NumReachedInlineCountMax,
4106f32e7eSjoerg "The # of times we reached inline count maximum");
4206f32e7eSjoerg
processCallEnter(NodeBuilderContext & BC,CallEnter CE,ExplodedNode * Pred)4306f32e7eSjoerg void ExprEngine::processCallEnter(NodeBuilderContext& BC, CallEnter CE,
4406f32e7eSjoerg ExplodedNode *Pred) {
4506f32e7eSjoerg // Get the entry block in the CFG of the callee.
4606f32e7eSjoerg const StackFrameContext *calleeCtx = CE.getCalleeContext();
4706f32e7eSjoerg PrettyStackTraceLocationContext CrashInfo(calleeCtx);
4806f32e7eSjoerg const CFGBlock *Entry = CE.getEntry();
4906f32e7eSjoerg
5006f32e7eSjoerg // Validate the CFG.
5106f32e7eSjoerg assert(Entry->empty());
5206f32e7eSjoerg assert(Entry->succ_size() == 1);
5306f32e7eSjoerg
5406f32e7eSjoerg // Get the solitary successor.
5506f32e7eSjoerg const CFGBlock *Succ = *(Entry->succ_begin());
5606f32e7eSjoerg
5706f32e7eSjoerg // Construct an edge representing the starting location in the callee.
5806f32e7eSjoerg BlockEdge Loc(Entry, Succ, calleeCtx);
5906f32e7eSjoerg
6006f32e7eSjoerg ProgramStateRef state = Pred->getState();
6106f32e7eSjoerg
6206f32e7eSjoerg // Construct a new node, notify checkers that analysis of the function has
6306f32e7eSjoerg // begun, and add the resultant nodes to the worklist.
6406f32e7eSjoerg bool isNew;
6506f32e7eSjoerg ExplodedNode *Node = G.getNode(Loc, state, false, &isNew);
6606f32e7eSjoerg Node->addPredecessor(Pred, G);
6706f32e7eSjoerg if (isNew) {
6806f32e7eSjoerg ExplodedNodeSet DstBegin;
6906f32e7eSjoerg processBeginOfFunction(BC, Node, DstBegin, Loc);
7006f32e7eSjoerg Engine.enqueue(DstBegin);
7106f32e7eSjoerg }
7206f32e7eSjoerg }
7306f32e7eSjoerg
7406f32e7eSjoerg // Find the last statement on the path to the exploded node and the
7506f32e7eSjoerg // corresponding Block.
7606f32e7eSjoerg static std::pair<const Stmt*,
getLastStmt(const ExplodedNode * Node)7706f32e7eSjoerg const CFGBlock*> getLastStmt(const ExplodedNode *Node) {
7806f32e7eSjoerg const Stmt *S = nullptr;
7906f32e7eSjoerg const CFGBlock *Blk = nullptr;
8006f32e7eSjoerg const StackFrameContext *SF = Node->getStackFrame();
8106f32e7eSjoerg
8206f32e7eSjoerg // Back up through the ExplodedGraph until we reach a statement node in this
8306f32e7eSjoerg // stack frame.
8406f32e7eSjoerg while (Node) {
8506f32e7eSjoerg const ProgramPoint &PP = Node->getLocation();
8606f32e7eSjoerg
8706f32e7eSjoerg if (PP.getStackFrame() == SF) {
8806f32e7eSjoerg if (Optional<StmtPoint> SP = PP.getAs<StmtPoint>()) {
8906f32e7eSjoerg S = SP->getStmt();
9006f32e7eSjoerg break;
9106f32e7eSjoerg } else if (Optional<CallExitEnd> CEE = PP.getAs<CallExitEnd>()) {
9206f32e7eSjoerg S = CEE->getCalleeContext()->getCallSite();
9306f32e7eSjoerg if (S)
9406f32e7eSjoerg break;
9506f32e7eSjoerg
9606f32e7eSjoerg // If there is no statement, this is an implicitly-generated call.
9706f32e7eSjoerg // We'll walk backwards over it and then continue the loop to find
9806f32e7eSjoerg // an actual statement.
9906f32e7eSjoerg Optional<CallEnter> CE;
10006f32e7eSjoerg do {
10106f32e7eSjoerg Node = Node->getFirstPred();
10206f32e7eSjoerg CE = Node->getLocationAs<CallEnter>();
10306f32e7eSjoerg } while (!CE || CE->getCalleeContext() != CEE->getCalleeContext());
10406f32e7eSjoerg
10506f32e7eSjoerg // Continue searching the graph.
10606f32e7eSjoerg } else if (Optional<BlockEdge> BE = PP.getAs<BlockEdge>()) {
10706f32e7eSjoerg Blk = BE->getSrc();
10806f32e7eSjoerg }
10906f32e7eSjoerg } else if (Optional<CallEnter> CE = PP.getAs<CallEnter>()) {
11006f32e7eSjoerg // If we reached the CallEnter for this function, it has no statements.
11106f32e7eSjoerg if (CE->getCalleeContext() == SF)
11206f32e7eSjoerg break;
11306f32e7eSjoerg }
11406f32e7eSjoerg
11506f32e7eSjoerg if (Node->pred_empty())
11606f32e7eSjoerg return std::make_pair(nullptr, nullptr);
11706f32e7eSjoerg
11806f32e7eSjoerg Node = *Node->pred_begin();
11906f32e7eSjoerg }
12006f32e7eSjoerg
12106f32e7eSjoerg return std::make_pair(S, Blk);
12206f32e7eSjoerg }
12306f32e7eSjoerg
12406f32e7eSjoerg /// Adjusts a return value when the called function's return type does not
12506f32e7eSjoerg /// match the caller's expression type. This can happen when a dynamic call
12606f32e7eSjoerg /// is devirtualized, and the overriding method has a covariant (more specific)
12706f32e7eSjoerg /// return type than the parent's method. For C++ objects, this means we need
12806f32e7eSjoerg /// to add base casts.
adjustReturnValue(SVal V,QualType ExpectedTy,QualType ActualTy,StoreManager & StoreMgr)12906f32e7eSjoerg static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy,
13006f32e7eSjoerg StoreManager &StoreMgr) {
13106f32e7eSjoerg // For now, the only adjustments we handle apply only to locations.
13206f32e7eSjoerg if (!V.getAs<Loc>())
13306f32e7eSjoerg return V;
13406f32e7eSjoerg
13506f32e7eSjoerg // If the types already match, don't do any unnecessary work.
13606f32e7eSjoerg ExpectedTy = ExpectedTy.getCanonicalType();
13706f32e7eSjoerg ActualTy = ActualTy.getCanonicalType();
13806f32e7eSjoerg if (ExpectedTy == ActualTy)
13906f32e7eSjoerg return V;
14006f32e7eSjoerg
14106f32e7eSjoerg // No adjustment is needed between Objective-C pointer types.
14206f32e7eSjoerg if (ExpectedTy->isObjCObjectPointerType() &&
14306f32e7eSjoerg ActualTy->isObjCObjectPointerType())
14406f32e7eSjoerg return V;
14506f32e7eSjoerg
14606f32e7eSjoerg // C++ object pointers may need "derived-to-base" casts.
14706f32e7eSjoerg const CXXRecordDecl *ExpectedClass = ExpectedTy->getPointeeCXXRecordDecl();
14806f32e7eSjoerg const CXXRecordDecl *ActualClass = ActualTy->getPointeeCXXRecordDecl();
14906f32e7eSjoerg if (ExpectedClass && ActualClass) {
15006f32e7eSjoerg CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
15106f32e7eSjoerg /*DetectVirtual=*/false);
15206f32e7eSjoerg if (ActualClass->isDerivedFrom(ExpectedClass, Paths) &&
15306f32e7eSjoerg !Paths.isAmbiguous(ActualTy->getCanonicalTypeUnqualified())) {
15406f32e7eSjoerg return StoreMgr.evalDerivedToBase(V, Paths.front());
15506f32e7eSjoerg }
15606f32e7eSjoerg }
15706f32e7eSjoerg
15806f32e7eSjoerg // Unfortunately, Objective-C does not enforce that overridden methods have
15906f32e7eSjoerg // covariant return types, so we can't assert that that never happens.
16006f32e7eSjoerg // Be safe and return UnknownVal().
16106f32e7eSjoerg return UnknownVal();
16206f32e7eSjoerg }
16306f32e7eSjoerg
removeDeadOnEndOfFunction(NodeBuilderContext & BC,ExplodedNode * Pred,ExplodedNodeSet & Dst)16406f32e7eSjoerg void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC,
16506f32e7eSjoerg ExplodedNode *Pred,
16606f32e7eSjoerg ExplodedNodeSet &Dst) {
16706f32e7eSjoerg // Find the last statement in the function and the corresponding basic block.
16806f32e7eSjoerg const Stmt *LastSt = nullptr;
16906f32e7eSjoerg const CFGBlock *Blk = nullptr;
17006f32e7eSjoerg std::tie(LastSt, Blk) = getLastStmt(Pred);
17106f32e7eSjoerg if (!Blk || !LastSt) {
17206f32e7eSjoerg Dst.Add(Pred);
17306f32e7eSjoerg return;
17406f32e7eSjoerg }
17506f32e7eSjoerg
17606f32e7eSjoerg // Here, we destroy the current location context. We use the current
17706f32e7eSjoerg // function's entire body as a diagnostic statement, with which the program
17806f32e7eSjoerg // point will be associated. However, we only want to use LastStmt as a
17906f32e7eSjoerg // reference for what to clean up if it's a ReturnStmt; otherwise, everything
18006f32e7eSjoerg // is dead.
18106f32e7eSjoerg SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC);
18206f32e7eSjoerg const LocationContext *LCtx = Pred->getLocationContext();
18306f32e7eSjoerg removeDead(Pred, Dst, dyn_cast<ReturnStmt>(LastSt), LCtx,
18406f32e7eSjoerg LCtx->getAnalysisDeclContext()->getBody(),
18506f32e7eSjoerg ProgramPoint::PostStmtPurgeDeadSymbolsKind);
18606f32e7eSjoerg }
18706f32e7eSjoerg
wasDifferentDeclUsedForInlining(CallEventRef<> Call,const StackFrameContext * calleeCtx)18806f32e7eSjoerg static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
18906f32e7eSjoerg const StackFrameContext *calleeCtx) {
19006f32e7eSjoerg const Decl *RuntimeCallee = calleeCtx->getDecl();
19106f32e7eSjoerg const Decl *StaticDecl = Call->getDecl();
19206f32e7eSjoerg assert(RuntimeCallee);
19306f32e7eSjoerg if (!StaticDecl)
19406f32e7eSjoerg return true;
19506f32e7eSjoerg return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl();
19606f32e7eSjoerg }
19706f32e7eSjoerg
19806f32e7eSjoerg /// The call exit is simulated with a sequence of nodes, which occur between
19906f32e7eSjoerg /// CallExitBegin and CallExitEnd. The following operations occur between the
20006f32e7eSjoerg /// two program points:
20106f32e7eSjoerg /// 1. CallExitBegin (triggers the start of call exit sequence)
20206f32e7eSjoerg /// 2. Bind the return value
20306f32e7eSjoerg /// 3. Run Remove dead bindings to clean up the dead symbols from the callee.
20406f32e7eSjoerg /// 4. CallExitEnd (switch to the caller context)
20506f32e7eSjoerg /// 5. PostStmt<CallExpr>
processCallExit(ExplodedNode * CEBNode)20606f32e7eSjoerg void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
20706f32e7eSjoerg // Step 1 CEBNode was generated before the call.
20806f32e7eSjoerg PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext());
20906f32e7eSjoerg const StackFrameContext *calleeCtx = CEBNode->getStackFrame();
21006f32e7eSjoerg
21106f32e7eSjoerg // The parent context might not be a stack frame, so make sure we
21206f32e7eSjoerg // look up the first enclosing stack frame.
21306f32e7eSjoerg const StackFrameContext *callerCtx =
21406f32e7eSjoerg calleeCtx->getParent()->getStackFrame();
21506f32e7eSjoerg
21606f32e7eSjoerg const Stmt *CE = calleeCtx->getCallSite();
21706f32e7eSjoerg ProgramStateRef state = CEBNode->getState();
21806f32e7eSjoerg // Find the last statement in the function and the corresponding basic block.
21906f32e7eSjoerg const Stmt *LastSt = nullptr;
22006f32e7eSjoerg const CFGBlock *Blk = nullptr;
22106f32e7eSjoerg std::tie(LastSt, Blk) = getLastStmt(CEBNode);
22206f32e7eSjoerg
22306f32e7eSjoerg // Generate a CallEvent /before/ cleaning the state, so that we can get the
22406f32e7eSjoerg // correct value for 'this' (if necessary).
22506f32e7eSjoerg CallEventManager &CEMgr = getStateManager().getCallEventManager();
22606f32e7eSjoerg CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state);
22706f32e7eSjoerg
22806f32e7eSjoerg // Step 2: generate node with bound return value: CEBNode -> BindedRetNode.
22906f32e7eSjoerg
23006f32e7eSjoerg // If the callee returns an expression, bind its value to CallExpr.
23106f32e7eSjoerg if (CE) {
23206f32e7eSjoerg if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
23306f32e7eSjoerg const LocationContext *LCtx = CEBNode->getLocationContext();
23406f32e7eSjoerg SVal V = state->getSVal(RS, LCtx);
23506f32e7eSjoerg
23606f32e7eSjoerg // Ensure that the return type matches the type of the returned Expr.
23706f32e7eSjoerg if (wasDifferentDeclUsedForInlining(Call, calleeCtx)) {
23806f32e7eSjoerg QualType ReturnedTy =
23906f32e7eSjoerg CallEvent::getDeclaredResultType(calleeCtx->getDecl());
24006f32e7eSjoerg if (!ReturnedTy.isNull()) {
24106f32e7eSjoerg if (const Expr *Ex = dyn_cast<Expr>(CE)) {
24206f32e7eSjoerg V = adjustReturnValue(V, Ex->getType(), ReturnedTy,
24306f32e7eSjoerg getStoreManager());
24406f32e7eSjoerg }
24506f32e7eSjoerg }
24606f32e7eSjoerg }
24706f32e7eSjoerg
24806f32e7eSjoerg state = state->BindExpr(CE, callerCtx, V);
24906f32e7eSjoerg }
25006f32e7eSjoerg
25106f32e7eSjoerg // Bind the constructed object value to CXXConstructExpr.
25206f32e7eSjoerg if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
25306f32e7eSjoerg loc::MemRegionVal This =
25406f32e7eSjoerg svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx);
25506f32e7eSjoerg SVal ThisV = state->getSVal(This);
25606f32e7eSjoerg ThisV = state->getSVal(ThisV.castAs<Loc>());
25706f32e7eSjoerg state = state->BindExpr(CCE, callerCtx, ThisV);
25806f32e7eSjoerg }
25906f32e7eSjoerg
26006f32e7eSjoerg if (const auto *CNE = dyn_cast<CXXNewExpr>(CE)) {
26106f32e7eSjoerg // We are currently evaluating a CXXNewAllocator CFGElement. It takes a
26206f32e7eSjoerg // while to reach the actual CXXNewExpr element from here, so keep the
26306f32e7eSjoerg // region for later use.
26406f32e7eSjoerg // Additionally cast the return value of the inlined operator new
26506f32e7eSjoerg // (which is of type 'void *') to the correct object type.
26606f32e7eSjoerg SVal AllocV = state->getSVal(CNE, callerCtx);
26706f32e7eSjoerg AllocV = svalBuilder.evalCast(
26806f32e7eSjoerg AllocV, CNE->getType(),
26906f32e7eSjoerg getContext().getPointerType(getContext().VoidTy));
27006f32e7eSjoerg
27106f32e7eSjoerg state = addObjectUnderConstruction(state, CNE, calleeCtx->getParent(),
27206f32e7eSjoerg AllocV);
27306f32e7eSjoerg }
27406f32e7eSjoerg }
27506f32e7eSjoerg
27606f32e7eSjoerg // Step 3: BindedRetNode -> CleanedNodes
27706f32e7eSjoerg // If we can find a statement and a block in the inlined function, run remove
27806f32e7eSjoerg // dead bindings before returning from the call. This is important to ensure
27906f32e7eSjoerg // that we report the issues such as leaks in the stack contexts in which
28006f32e7eSjoerg // they occurred.
28106f32e7eSjoerg ExplodedNodeSet CleanedNodes;
28206f32e7eSjoerg if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) {
28306f32e7eSjoerg static SimpleProgramPointTag retValBind("ExprEngine", "Bind Return Value");
28406f32e7eSjoerg PostStmt Loc(LastSt, calleeCtx, &retValBind);
28506f32e7eSjoerg bool isNew;
28606f32e7eSjoerg ExplodedNode *BindedRetNode = G.getNode(Loc, state, false, &isNew);
28706f32e7eSjoerg BindedRetNode->addPredecessor(CEBNode, G);
28806f32e7eSjoerg if (!isNew)
28906f32e7eSjoerg return;
29006f32e7eSjoerg
29106f32e7eSjoerg NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode);
29206f32e7eSjoerg currBldrCtx = &Ctx;
29306f32e7eSjoerg // Here, we call the Symbol Reaper with 0 statement and callee location
29406f32e7eSjoerg // context, telling it to clean up everything in the callee's context
29506f32e7eSjoerg // (and its children). We use the callee's function body as a diagnostic
29606f32e7eSjoerg // statement, with which the program point will be associated.
29706f32e7eSjoerg removeDead(BindedRetNode, CleanedNodes, nullptr, calleeCtx,
29806f32e7eSjoerg calleeCtx->getAnalysisDeclContext()->getBody(),
29906f32e7eSjoerg ProgramPoint::PostStmtPurgeDeadSymbolsKind);
30006f32e7eSjoerg currBldrCtx = nullptr;
30106f32e7eSjoerg } else {
30206f32e7eSjoerg CleanedNodes.Add(CEBNode);
30306f32e7eSjoerg }
30406f32e7eSjoerg
30506f32e7eSjoerg for (ExplodedNodeSet::iterator I = CleanedNodes.begin(),
30606f32e7eSjoerg E = CleanedNodes.end(); I != E; ++I) {
30706f32e7eSjoerg
30806f32e7eSjoerg // Step 4: Generate the CallExit and leave the callee's context.
30906f32e7eSjoerg // CleanedNodes -> CEENode
31006f32e7eSjoerg CallExitEnd Loc(calleeCtx, callerCtx);
31106f32e7eSjoerg bool isNew;
31206f32e7eSjoerg ProgramStateRef CEEState = (*I == CEBNode) ? state : (*I)->getState();
31306f32e7eSjoerg
31406f32e7eSjoerg ExplodedNode *CEENode = G.getNode(Loc, CEEState, false, &isNew);
31506f32e7eSjoerg CEENode->addPredecessor(*I, G);
31606f32e7eSjoerg if (!isNew)
31706f32e7eSjoerg return;
31806f32e7eSjoerg
31906f32e7eSjoerg // Step 5: Perform the post-condition check of the CallExpr and enqueue the
32006f32e7eSjoerg // result onto the work list.
32106f32e7eSjoerg // CEENode -> Dst -> WorkList
32206f32e7eSjoerg NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode);
32306f32e7eSjoerg SaveAndRestore<const NodeBuilderContext*> NBCSave(currBldrCtx,
32406f32e7eSjoerg &Ctx);
32506f32e7eSjoerg SaveAndRestore<unsigned> CBISave(currStmtIdx, calleeCtx->getIndex());
32606f32e7eSjoerg
32706f32e7eSjoerg CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState);
32806f32e7eSjoerg
32906f32e7eSjoerg ExplodedNodeSet DstPostCall;
330*13fbcb42Sjoerg if (llvm::isa_and_nonnull<CXXNewExpr>(CE)) {
33106f32e7eSjoerg ExplodedNodeSet DstPostPostCallCallback;
33206f32e7eSjoerg getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback,
33306f32e7eSjoerg CEENode, *UpdatedCall, *this,
33406f32e7eSjoerg /*wasInlined=*/true);
335*13fbcb42Sjoerg for (ExplodedNode *I : DstPostPostCallCallback) {
33606f32e7eSjoerg getCheckerManager().runCheckersForNewAllocator(
337*13fbcb42Sjoerg cast<CXXAllocatorCall>(*UpdatedCall), DstPostCall, I, *this,
33806f32e7eSjoerg /*wasInlined=*/true);
33906f32e7eSjoerg }
34006f32e7eSjoerg } else {
34106f32e7eSjoerg getCheckerManager().runCheckersForPostCall(DstPostCall, CEENode,
34206f32e7eSjoerg *UpdatedCall, *this,
34306f32e7eSjoerg /*wasInlined=*/true);
34406f32e7eSjoerg }
34506f32e7eSjoerg ExplodedNodeSet Dst;
34606f32e7eSjoerg if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {
34706f32e7eSjoerg getCheckerManager().runCheckersForPostObjCMessage(Dst, DstPostCall, *Msg,
34806f32e7eSjoerg *this,
34906f32e7eSjoerg /*wasInlined=*/true);
35006f32e7eSjoerg } else if (CE &&
35106f32e7eSjoerg !(isa<CXXNewExpr>(CE) && // Called when visiting CXXNewExpr.
35206f32e7eSjoerg AMgr.getAnalyzerOptions().MayInlineCXXAllocator)) {
35306f32e7eSjoerg getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE,
35406f32e7eSjoerg *this, /*wasInlined=*/true);
35506f32e7eSjoerg } else {
35606f32e7eSjoerg Dst.insert(DstPostCall);
35706f32e7eSjoerg }
35806f32e7eSjoerg
35906f32e7eSjoerg // Enqueue the next element in the block.
36006f32e7eSjoerg for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end();
36106f32e7eSjoerg PSI != PSE; ++PSI) {
36206f32e7eSjoerg Engine.getWorkList()->enqueue(*PSI, calleeCtx->getCallSiteBlock(),
36306f32e7eSjoerg calleeCtx->getIndex()+1);
36406f32e7eSjoerg }
36506f32e7eSjoerg }
36606f32e7eSjoerg }
36706f32e7eSjoerg
isSmall(AnalysisDeclContext * ADC) const36806f32e7eSjoerg bool ExprEngine::isSmall(AnalysisDeclContext *ADC) const {
36906f32e7eSjoerg // When there are no branches in the function, it means that there's no
37006f32e7eSjoerg // exponential complexity introduced by inlining such function.
37106f32e7eSjoerg // Such functions also don't trigger various fundamental problems
37206f32e7eSjoerg // with our inlining mechanism, such as the problem of
37306f32e7eSjoerg // inlined defensive checks. Hence isLinear().
37406f32e7eSjoerg const CFG *Cfg = ADC->getCFG();
37506f32e7eSjoerg return Cfg->isLinear() || Cfg->size() <= AMgr.options.AlwaysInlineSize;
37606f32e7eSjoerg }
37706f32e7eSjoerg
isLarge(AnalysisDeclContext * ADC) const37806f32e7eSjoerg bool ExprEngine::isLarge(AnalysisDeclContext *ADC) const {
37906f32e7eSjoerg const CFG *Cfg = ADC->getCFG();
38006f32e7eSjoerg return Cfg->size() >= AMgr.options.MinCFGSizeTreatFunctionsAsLarge;
38106f32e7eSjoerg }
38206f32e7eSjoerg
isHuge(AnalysisDeclContext * ADC) const38306f32e7eSjoerg bool ExprEngine::isHuge(AnalysisDeclContext *ADC) const {
38406f32e7eSjoerg const CFG *Cfg = ADC->getCFG();
38506f32e7eSjoerg return Cfg->getNumBlockIDs() > AMgr.options.MaxInlinableSize;
38606f32e7eSjoerg }
38706f32e7eSjoerg
examineStackFrames(const Decl * D,const LocationContext * LCtx,bool & IsRecursive,unsigned & StackDepth)38806f32e7eSjoerg void ExprEngine::examineStackFrames(const Decl *D, const LocationContext *LCtx,
38906f32e7eSjoerg bool &IsRecursive, unsigned &StackDepth) {
39006f32e7eSjoerg IsRecursive = false;
39106f32e7eSjoerg StackDepth = 0;
39206f32e7eSjoerg
39306f32e7eSjoerg while (LCtx) {
39406f32e7eSjoerg if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LCtx)) {
39506f32e7eSjoerg const Decl *DI = SFC->getDecl();
39606f32e7eSjoerg
39706f32e7eSjoerg // Mark recursive (and mutually recursive) functions and always count
39806f32e7eSjoerg // them when measuring the stack depth.
39906f32e7eSjoerg if (DI == D) {
40006f32e7eSjoerg IsRecursive = true;
40106f32e7eSjoerg ++StackDepth;
40206f32e7eSjoerg LCtx = LCtx->getParent();
40306f32e7eSjoerg continue;
40406f32e7eSjoerg }
40506f32e7eSjoerg
40606f32e7eSjoerg // Do not count the small functions when determining the stack depth.
40706f32e7eSjoerg AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(DI);
40806f32e7eSjoerg if (!isSmall(CalleeADC))
40906f32e7eSjoerg ++StackDepth;
41006f32e7eSjoerg }
41106f32e7eSjoerg LCtx = LCtx->getParent();
41206f32e7eSjoerg }
41306f32e7eSjoerg }
41406f32e7eSjoerg
41506f32e7eSjoerg // The GDM component containing the dynamic dispatch bifurcation info. When
41606f32e7eSjoerg // the exact type of the receiver is not known, we want to explore both paths -
41706f32e7eSjoerg // one on which we do inline it and the other one on which we don't. This is
41806f32e7eSjoerg // done to ensure we do not drop coverage.
41906f32e7eSjoerg // This is the map from the receiver region to a bool, specifying either we
42006f32e7eSjoerg // consider this region's information precise or not along the given path.
42106f32e7eSjoerg namespace {
42206f32e7eSjoerg enum DynamicDispatchMode {
42306f32e7eSjoerg DynamicDispatchModeInlined = 1,
42406f32e7eSjoerg DynamicDispatchModeConservative
42506f32e7eSjoerg };
42606f32e7eSjoerg } // end anonymous namespace
42706f32e7eSjoerg
REGISTER_MAP_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap,const MemRegion *,unsigned)42806f32e7eSjoerg REGISTER_MAP_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap,
42906f32e7eSjoerg const MemRegion *, unsigned)
43006f32e7eSjoerg
43106f32e7eSjoerg bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
43206f32e7eSjoerg NodeBuilder &Bldr, ExplodedNode *Pred,
43306f32e7eSjoerg ProgramStateRef State) {
43406f32e7eSjoerg assert(D);
43506f32e7eSjoerg
43606f32e7eSjoerg const LocationContext *CurLC = Pred->getLocationContext();
43706f32e7eSjoerg const StackFrameContext *CallerSFC = CurLC->getStackFrame();
43806f32e7eSjoerg const LocationContext *ParentOfCallee = CallerSFC;
43906f32e7eSjoerg if (Call.getKind() == CE_Block &&
44006f32e7eSjoerg !cast<BlockCall>(Call).isConversionFromLambda()) {
44106f32e7eSjoerg const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
44206f32e7eSjoerg assert(BR && "If we have the block definition we should have its region");
44306f32e7eSjoerg AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
44406f32e7eSjoerg ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
44506f32e7eSjoerg cast<BlockDecl>(D),
44606f32e7eSjoerg BR);
44706f32e7eSjoerg }
44806f32e7eSjoerg
44906f32e7eSjoerg // This may be NULL, but that's fine.
45006f32e7eSjoerg const Expr *CallE = Call.getOriginExpr();
45106f32e7eSjoerg
45206f32e7eSjoerg // Construct a new stack frame for the callee.
45306f32e7eSjoerg AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
45406f32e7eSjoerg const StackFrameContext *CalleeSFC =
45506f32e7eSjoerg CalleeADC->getStackFrame(ParentOfCallee, CallE, currBldrCtx->getBlock(),
45606f32e7eSjoerg currBldrCtx->blockCount(), currStmtIdx);
45706f32e7eSjoerg
45806f32e7eSjoerg CallEnter Loc(CallE, CalleeSFC, CurLC);
45906f32e7eSjoerg
46006f32e7eSjoerg // Construct a new state which contains the mapping from actual to
46106f32e7eSjoerg // formal arguments.
46206f32e7eSjoerg State = State->enterStackFrame(Call, CalleeSFC);
46306f32e7eSjoerg
46406f32e7eSjoerg bool isNew;
46506f32e7eSjoerg if (ExplodedNode *N = G.getNode(Loc, State, false, &isNew)) {
46606f32e7eSjoerg N->addPredecessor(Pred, G);
46706f32e7eSjoerg if (isNew)
46806f32e7eSjoerg Engine.getWorkList()->enqueue(N);
46906f32e7eSjoerg }
47006f32e7eSjoerg
47106f32e7eSjoerg // If we decided to inline the call, the successor has been manually
47206f32e7eSjoerg // added onto the work list so remove it from the node builder.
47306f32e7eSjoerg Bldr.takeNodes(Pred);
47406f32e7eSjoerg
47506f32e7eSjoerg NumInlinedCalls++;
47606f32e7eSjoerg Engine.FunctionSummaries->bumpNumTimesInlined(D);
47706f32e7eSjoerg
47806f32e7eSjoerg // Mark the decl as visited.
47906f32e7eSjoerg if (VisitedCallees)
48006f32e7eSjoerg VisitedCallees->insert(D);
48106f32e7eSjoerg
48206f32e7eSjoerg return true;
48306f32e7eSjoerg }
48406f32e7eSjoerg
getInlineFailedState(ProgramStateRef State,const Stmt * CallE)48506f32e7eSjoerg static ProgramStateRef getInlineFailedState(ProgramStateRef State,
48606f32e7eSjoerg const Stmt *CallE) {
48706f32e7eSjoerg const void *ReplayState = State->get<ReplayWithoutInlining>();
48806f32e7eSjoerg if (!ReplayState)
48906f32e7eSjoerg return nullptr;
49006f32e7eSjoerg
49106f32e7eSjoerg assert(ReplayState == CallE && "Backtracked to the wrong call.");
49206f32e7eSjoerg (void)CallE;
49306f32e7eSjoerg
49406f32e7eSjoerg return State->remove<ReplayWithoutInlining>();
49506f32e7eSjoerg }
49606f32e7eSjoerg
VisitCallExpr(const CallExpr * CE,ExplodedNode * Pred,ExplodedNodeSet & dst)49706f32e7eSjoerg void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
49806f32e7eSjoerg ExplodedNodeSet &dst) {
49906f32e7eSjoerg // Perform the previsit of the CallExpr.
50006f32e7eSjoerg ExplodedNodeSet dstPreVisit;
50106f32e7eSjoerg getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this);
50206f32e7eSjoerg
50306f32e7eSjoerg // Get the call in its initial state. We use this as a template to perform
50406f32e7eSjoerg // all the checks.
50506f32e7eSjoerg CallEventManager &CEMgr = getStateManager().getCallEventManager();
50606f32e7eSjoerg CallEventRef<> CallTemplate
50706f32e7eSjoerg = CEMgr.getSimpleCall(CE, Pred->getState(), Pred->getLocationContext());
50806f32e7eSjoerg
50906f32e7eSjoerg // Evaluate the function call. We try each of the checkers
51006f32e7eSjoerg // to see if the can evaluate the function call.
51106f32e7eSjoerg ExplodedNodeSet dstCallEvaluated;
51206f32e7eSjoerg for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
51306f32e7eSjoerg I != E; ++I) {
51406f32e7eSjoerg evalCall(dstCallEvaluated, *I, *CallTemplate);
51506f32e7eSjoerg }
51606f32e7eSjoerg
51706f32e7eSjoerg // Finally, perform the post-condition check of the CallExpr and store
51806f32e7eSjoerg // the created nodes in 'Dst'.
51906f32e7eSjoerg // Note that if the call was inlined, dstCallEvaluated will be empty.
52006f32e7eSjoerg // The post-CallExpr check will occur in processCallExit.
52106f32e7eSjoerg getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE,
52206f32e7eSjoerg *this);
52306f32e7eSjoerg }
52406f32e7eSjoerg
finishArgumentConstruction(ProgramStateRef State,const CallEvent & Call)52506f32e7eSjoerg ProgramStateRef ExprEngine::finishArgumentConstruction(ProgramStateRef State,
52606f32e7eSjoerg const CallEvent &Call) {
52706f32e7eSjoerg const Expr *E = Call.getOriginExpr();
52806f32e7eSjoerg // FIXME: Constructors to placement arguments of operator new
52906f32e7eSjoerg // are not supported yet.
53006f32e7eSjoerg if (!E || isa<CXXNewExpr>(E))
53106f32e7eSjoerg return State;
53206f32e7eSjoerg
53306f32e7eSjoerg const LocationContext *LC = Call.getLocationContext();
53406f32e7eSjoerg for (unsigned CallI = 0, CallN = Call.getNumArgs(); CallI != CallN; ++CallI) {
53506f32e7eSjoerg unsigned I = Call.getASTArgumentIndex(CallI);
53606f32e7eSjoerg if (Optional<SVal> V =
53706f32e7eSjoerg getObjectUnderConstruction(State, {E, I}, LC)) {
53806f32e7eSjoerg SVal VV = *V;
53906f32e7eSjoerg (void)VV;
54006f32e7eSjoerg assert(cast<VarRegion>(VV.castAs<loc::MemRegionVal>().getRegion())
54106f32e7eSjoerg ->getStackFrame()->getParent()
54206f32e7eSjoerg ->getStackFrame() == LC->getStackFrame());
54306f32e7eSjoerg State = finishObjectConstruction(State, {E, I}, LC);
54406f32e7eSjoerg }
54506f32e7eSjoerg }
54606f32e7eSjoerg
54706f32e7eSjoerg return State;
54806f32e7eSjoerg }
54906f32e7eSjoerg
finishArgumentConstruction(ExplodedNodeSet & Dst,ExplodedNode * Pred,const CallEvent & Call)55006f32e7eSjoerg void ExprEngine::finishArgumentConstruction(ExplodedNodeSet &Dst,
55106f32e7eSjoerg ExplodedNode *Pred,
55206f32e7eSjoerg const CallEvent &Call) {
55306f32e7eSjoerg ProgramStateRef State = Pred->getState();
55406f32e7eSjoerg ProgramStateRef CleanedState = finishArgumentConstruction(State, Call);
55506f32e7eSjoerg if (CleanedState == State) {
55606f32e7eSjoerg Dst.insert(Pred);
55706f32e7eSjoerg return;
55806f32e7eSjoerg }
55906f32e7eSjoerg
56006f32e7eSjoerg const Expr *E = Call.getOriginExpr();
56106f32e7eSjoerg const LocationContext *LC = Call.getLocationContext();
56206f32e7eSjoerg NodeBuilder B(Pred, Dst, *currBldrCtx);
56306f32e7eSjoerg static SimpleProgramPointTag Tag("ExprEngine",
56406f32e7eSjoerg "Finish argument construction");
56506f32e7eSjoerg PreStmt PP(E, LC, &Tag);
56606f32e7eSjoerg B.generateNode(PP, CleanedState, Pred);
56706f32e7eSjoerg }
56806f32e7eSjoerg
evalCall(ExplodedNodeSet & Dst,ExplodedNode * Pred,const CallEvent & Call)56906f32e7eSjoerg void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
57006f32e7eSjoerg const CallEvent &Call) {
57106f32e7eSjoerg // WARNING: At this time, the state attached to 'Call' may be older than the
57206f32e7eSjoerg // state in 'Pred'. This is a minor optimization since CheckerManager will
57306f32e7eSjoerg // use an updated CallEvent instance when calling checkers, but if 'Call' is
57406f32e7eSjoerg // ever used directly in this function all callers should be updated to pass
57506f32e7eSjoerg // the most recent state. (It is probably not worth doing the work here since
57606f32e7eSjoerg // for some callers this will not be necessary.)
57706f32e7eSjoerg
57806f32e7eSjoerg // Run any pre-call checks using the generic call interface.
57906f32e7eSjoerg ExplodedNodeSet dstPreVisit;
58006f32e7eSjoerg getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred,
58106f32e7eSjoerg Call, *this);
58206f32e7eSjoerg
58306f32e7eSjoerg // Actually evaluate the function call. We try each of the checkers
58406f32e7eSjoerg // to see if the can evaluate the function call, and get a callback at
58506f32e7eSjoerg // defaultEvalCall if all of them fail.
58606f32e7eSjoerg ExplodedNodeSet dstCallEvaluated;
58706f32e7eSjoerg getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,
588*13fbcb42Sjoerg Call, *this, EvalCallOptions());
58906f32e7eSjoerg
59006f32e7eSjoerg // If there were other constructors called for object-type arguments
59106f32e7eSjoerg // of this call, clean them up.
59206f32e7eSjoerg ExplodedNodeSet dstArgumentCleanup;
593*13fbcb42Sjoerg for (ExplodedNode *I : dstCallEvaluated)
59406f32e7eSjoerg finishArgumentConstruction(dstArgumentCleanup, I, Call);
59506f32e7eSjoerg
596*13fbcb42Sjoerg ExplodedNodeSet dstPostCall;
597*13fbcb42Sjoerg getCheckerManager().runCheckersForPostCall(dstPostCall, dstArgumentCleanup,
59806f32e7eSjoerg Call, *this);
599*13fbcb42Sjoerg
600*13fbcb42Sjoerg // Escaping symbols conjured during invalidating the regions above.
601*13fbcb42Sjoerg // Note that, for inlined calls the nodes were put back into the worklist,
602*13fbcb42Sjoerg // so we can assume that every node belongs to a conservative call at this
603*13fbcb42Sjoerg // point.
604*13fbcb42Sjoerg
605*13fbcb42Sjoerg // Run pointerEscape callback with the newly conjured symbols.
606*13fbcb42Sjoerg SmallVector<std::pair<SVal, SVal>, 8> Escaped;
607*13fbcb42Sjoerg for (ExplodedNode *I : dstPostCall) {
608*13fbcb42Sjoerg NodeBuilder B(I, Dst, *currBldrCtx);
609*13fbcb42Sjoerg ProgramStateRef State = I->getState();
610*13fbcb42Sjoerg Escaped.clear();
611*13fbcb42Sjoerg {
612*13fbcb42Sjoerg unsigned Arg = -1;
613*13fbcb42Sjoerg for (const ParmVarDecl *PVD : Call.parameters()) {
614*13fbcb42Sjoerg ++Arg;
615*13fbcb42Sjoerg QualType ParamTy = PVD->getType();
616*13fbcb42Sjoerg if (ParamTy.isNull() ||
617*13fbcb42Sjoerg (!ParamTy->isPointerType() && !ParamTy->isReferenceType()))
618*13fbcb42Sjoerg continue;
619*13fbcb42Sjoerg QualType Pointee = ParamTy->getPointeeType();
620*13fbcb42Sjoerg if (Pointee.isConstQualified() || Pointee->isVoidType())
621*13fbcb42Sjoerg continue;
622*13fbcb42Sjoerg if (const MemRegion *MR = Call.getArgSVal(Arg).getAsRegion())
623*13fbcb42Sjoerg Escaped.emplace_back(loc::MemRegionVal(MR), State->getSVal(MR, Pointee));
624*13fbcb42Sjoerg }
625*13fbcb42Sjoerg }
626*13fbcb42Sjoerg
627*13fbcb42Sjoerg State = processPointerEscapedOnBind(State, Escaped, I->getLocationContext(),
628*13fbcb42Sjoerg PSK_EscapeOutParameters, &Call);
629*13fbcb42Sjoerg
630*13fbcb42Sjoerg if (State == I->getState())
631*13fbcb42Sjoerg Dst.insert(I);
632*13fbcb42Sjoerg else
633*13fbcb42Sjoerg B.generateNode(I->getLocation(), State, I);
634*13fbcb42Sjoerg }
63506f32e7eSjoerg }
63606f32e7eSjoerg
bindReturnValue(const CallEvent & Call,const LocationContext * LCtx,ProgramStateRef State)63706f32e7eSjoerg ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
63806f32e7eSjoerg const LocationContext *LCtx,
63906f32e7eSjoerg ProgramStateRef State) {
64006f32e7eSjoerg const Expr *E = Call.getOriginExpr();
64106f32e7eSjoerg if (!E)
64206f32e7eSjoerg return State;
64306f32e7eSjoerg
64406f32e7eSjoerg // Some method families have known return values.
64506f32e7eSjoerg if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
64606f32e7eSjoerg switch (Msg->getMethodFamily()) {
64706f32e7eSjoerg default:
64806f32e7eSjoerg break;
64906f32e7eSjoerg case OMF_autorelease:
65006f32e7eSjoerg case OMF_retain:
65106f32e7eSjoerg case OMF_self: {
65206f32e7eSjoerg // These methods return their receivers.
65306f32e7eSjoerg return State->BindExpr(E, LCtx, Msg->getReceiverSVal());
65406f32e7eSjoerg }
65506f32e7eSjoerg }
65606f32e7eSjoerg } else if (const CXXConstructorCall *C = dyn_cast<CXXConstructorCall>(&Call)){
65706f32e7eSjoerg SVal ThisV = C->getCXXThisVal();
65806f32e7eSjoerg ThisV = State->getSVal(ThisV.castAs<Loc>());
65906f32e7eSjoerg return State->BindExpr(E, LCtx, ThisV);
66006f32e7eSjoerg }
66106f32e7eSjoerg
66206f32e7eSjoerg SVal R;
66306f32e7eSjoerg QualType ResultTy = Call.getResultType();
66406f32e7eSjoerg unsigned Count = currBldrCtx->blockCount();
66506f32e7eSjoerg if (auto RTC = getCurrentCFGElement().getAs<CFGCXXRecordTypedCall>()) {
66606f32e7eSjoerg // Conjure a temporary if the function returns an object by value.
66706f32e7eSjoerg SVal Target;
66806f32e7eSjoerg assert(RTC->getStmt() == Call.getOriginExpr());
66906f32e7eSjoerg EvalCallOptions CallOpts; // FIXME: We won't really need those.
67006f32e7eSjoerg std::tie(State, Target) =
671*13fbcb42Sjoerg handleConstructionContext(Call.getOriginExpr(), State, LCtx,
67206f32e7eSjoerg RTC->getConstructionContext(), CallOpts);
67306f32e7eSjoerg const MemRegion *TargetR = Target.getAsRegion();
67406f32e7eSjoerg assert(TargetR);
67506f32e7eSjoerg // Invalidate the region so that it didn't look uninitialized. If this is
67606f32e7eSjoerg // a field or element constructor, we do not want to invalidate
67706f32e7eSjoerg // the whole structure. Pointer escape is meaningless because
67806f32e7eSjoerg // the structure is a product of conservative evaluation
67906f32e7eSjoerg // and therefore contains nothing interesting at this point.
68006f32e7eSjoerg RegionAndSymbolInvalidationTraits ITraits;
68106f32e7eSjoerg ITraits.setTrait(TargetR,
68206f32e7eSjoerg RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
68306f32e7eSjoerg State = State->invalidateRegions(TargetR, E, Count, LCtx,
68406f32e7eSjoerg /* CausesPointerEscape=*/false, nullptr,
68506f32e7eSjoerg &Call, &ITraits);
68606f32e7eSjoerg
68706f32e7eSjoerg R = State->getSVal(Target.castAs<Loc>(), E->getType());
68806f32e7eSjoerg } else {
68906f32e7eSjoerg // Conjure a symbol if the return value is unknown.
69006f32e7eSjoerg
69106f32e7eSjoerg // See if we need to conjure a heap pointer instead of
69206f32e7eSjoerg // a regular unknown pointer.
693*13fbcb42Sjoerg const auto *CNE = dyn_cast<CXXNewExpr>(E);
694*13fbcb42Sjoerg if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
695*13fbcb42Sjoerg R = svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count);
696*13fbcb42Sjoerg const MemRegion *MR = R.getAsRegion()->StripCasts();
697*13fbcb42Sjoerg
698*13fbcb42Sjoerg // Store the extent of the allocated object(s).
699*13fbcb42Sjoerg SVal ElementCount;
700*13fbcb42Sjoerg if (const Expr *SizeExpr = CNE->getArraySize().getValueOr(nullptr)) {
701*13fbcb42Sjoerg ElementCount = State->getSVal(SizeExpr, LCtx);
702*13fbcb42Sjoerg } else {
703*13fbcb42Sjoerg ElementCount = svalBuilder.makeIntVal(1, /*IsUnsigned=*/true);
70406f32e7eSjoerg }
70506f32e7eSjoerg
706*13fbcb42Sjoerg SVal ElementSize = getElementExtent(CNE->getAllocatedType(), svalBuilder);
707*13fbcb42Sjoerg
708*13fbcb42Sjoerg SVal Size =
709*13fbcb42Sjoerg svalBuilder.evalBinOp(State, BO_Mul, ElementCount, ElementSize,
710*13fbcb42Sjoerg svalBuilder.getArrayIndexType());
711*13fbcb42Sjoerg
712*13fbcb42Sjoerg State = setDynamicExtent(State, MR, Size.castAs<DefinedOrUnknownSVal>(),
713*13fbcb42Sjoerg svalBuilder);
714*13fbcb42Sjoerg } else {
715*13fbcb42Sjoerg R = svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count);
716*13fbcb42Sjoerg }
71706f32e7eSjoerg }
71806f32e7eSjoerg return State->BindExpr(E, LCtx, R);
71906f32e7eSjoerg }
72006f32e7eSjoerg
72106f32e7eSjoerg // Conservatively evaluate call by invalidating regions and binding
72206f32e7eSjoerg // a conjured return value.
conservativeEvalCall(const CallEvent & Call,NodeBuilder & Bldr,ExplodedNode * Pred,ProgramStateRef State)72306f32e7eSjoerg void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
724*13fbcb42Sjoerg ExplodedNode *Pred, ProgramStateRef State) {
72506f32e7eSjoerg State = Call.invalidateRegions(currBldrCtx->blockCount(), State);
72606f32e7eSjoerg State = bindReturnValue(Call, Pred->getLocationContext(), State);
72706f32e7eSjoerg
72806f32e7eSjoerg // And make the result node.
72906f32e7eSjoerg Bldr.generateNode(Call.getProgramPoint(), State, Pred);
73006f32e7eSjoerg }
73106f32e7eSjoerg
73206f32e7eSjoerg ExprEngine::CallInlinePolicy
mayInlineCallKind(const CallEvent & Call,const ExplodedNode * Pred,AnalyzerOptions & Opts,const EvalCallOptions & CallOpts)73306f32e7eSjoerg ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
73406f32e7eSjoerg AnalyzerOptions &Opts,
735*13fbcb42Sjoerg const EvalCallOptions &CallOpts) {
73606f32e7eSjoerg const LocationContext *CurLC = Pred->getLocationContext();
73706f32e7eSjoerg const StackFrameContext *CallerSFC = CurLC->getStackFrame();
73806f32e7eSjoerg switch (Call.getKind()) {
73906f32e7eSjoerg case CE_Function:
74006f32e7eSjoerg case CE_Block:
74106f32e7eSjoerg break;
74206f32e7eSjoerg case CE_CXXMember:
74306f32e7eSjoerg case CE_CXXMemberOperator:
74406f32e7eSjoerg if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions))
74506f32e7eSjoerg return CIP_DisallowedAlways;
74606f32e7eSjoerg break;
74706f32e7eSjoerg case CE_CXXConstructor: {
74806f32e7eSjoerg if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors))
74906f32e7eSjoerg return CIP_DisallowedAlways;
75006f32e7eSjoerg
75106f32e7eSjoerg const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call);
75206f32e7eSjoerg
75306f32e7eSjoerg const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
75406f32e7eSjoerg
75506f32e7eSjoerg auto CCE = getCurrentCFGElement().getAs<CFGConstructor>();
75606f32e7eSjoerg const ConstructionContext *CC = CCE ? CCE->getConstructionContext()
75706f32e7eSjoerg : nullptr;
75806f32e7eSjoerg
759*13fbcb42Sjoerg if (llvm::isa_and_nonnull<NewAllocatedObjectConstructionContext>(CC) &&
76006f32e7eSjoerg !Opts.MayInlineCXXAllocator)
76106f32e7eSjoerg return CIP_DisallowedOnce;
76206f32e7eSjoerg
76306f32e7eSjoerg // FIXME: We don't handle constructors or destructors for arrays properly.
76406f32e7eSjoerg // Even once we do, we still need to be careful about implicitly-generated
76506f32e7eSjoerg // initializers for array fields in default move/copy constructors.
76606f32e7eSjoerg // We still allow construction into ElementRegion targets when they don't
76706f32e7eSjoerg // represent array elements.
76806f32e7eSjoerg if (CallOpts.IsArrayCtorOrDtor)
76906f32e7eSjoerg return CIP_DisallowedOnce;
77006f32e7eSjoerg
77106f32e7eSjoerg // Inlining constructors requires including initializers in the CFG.
77206f32e7eSjoerg const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
77306f32e7eSjoerg assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers");
77406f32e7eSjoerg (void)ADC;
77506f32e7eSjoerg
77606f32e7eSjoerg // If the destructor is trivial, it's always safe to inline the constructor.
77706f32e7eSjoerg if (Ctor.getDecl()->getParent()->hasTrivialDestructor())
77806f32e7eSjoerg break;
77906f32e7eSjoerg
78006f32e7eSjoerg // For other types, only inline constructors if destructor inlining is
78106f32e7eSjoerg // also enabled.
78206f32e7eSjoerg if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
78306f32e7eSjoerg return CIP_DisallowedAlways;
78406f32e7eSjoerg
78506f32e7eSjoerg if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) {
78606f32e7eSjoerg // If we don't handle temporary destructors, we shouldn't inline
78706f32e7eSjoerg // their constructors.
78806f32e7eSjoerg if (CallOpts.IsTemporaryCtorOrDtor &&
78906f32e7eSjoerg !Opts.ShouldIncludeTemporaryDtorsInCFG)
79006f32e7eSjoerg return CIP_DisallowedOnce;
79106f32e7eSjoerg
79206f32e7eSjoerg // If we did not find the correct this-region, it would be pointless
79306f32e7eSjoerg // to inline the constructor. Instead we will simply invalidate
79406f32e7eSjoerg // the fake temporary target.
79506f32e7eSjoerg if (CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion)
79606f32e7eSjoerg return CIP_DisallowedOnce;
79706f32e7eSjoerg
79806f32e7eSjoerg // If the temporary is lifetime-extended by binding it to a reference-type
79906f32e7eSjoerg // field within an aggregate, automatic destructors don't work properly.
80006f32e7eSjoerg if (CallOpts.IsTemporaryLifetimeExtendedViaAggregate)
80106f32e7eSjoerg return CIP_DisallowedOnce;
80206f32e7eSjoerg }
80306f32e7eSjoerg
80406f32e7eSjoerg break;
80506f32e7eSjoerg }
806*13fbcb42Sjoerg case CE_CXXInheritedConstructor: {
807*13fbcb42Sjoerg // This doesn't really increase the cost of inlining ever, because
808*13fbcb42Sjoerg // the stack frame of the inherited constructor is trivial.
809*13fbcb42Sjoerg return CIP_Allowed;
810*13fbcb42Sjoerg }
81106f32e7eSjoerg case CE_CXXDestructor: {
81206f32e7eSjoerg if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
81306f32e7eSjoerg return CIP_DisallowedAlways;
81406f32e7eSjoerg
81506f32e7eSjoerg // Inlining destructors requires building the CFG correctly.
81606f32e7eSjoerg const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
81706f32e7eSjoerg assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors");
81806f32e7eSjoerg (void)ADC;
81906f32e7eSjoerg
82006f32e7eSjoerg // FIXME: We don't handle constructors or destructors for arrays properly.
82106f32e7eSjoerg if (CallOpts.IsArrayCtorOrDtor)
82206f32e7eSjoerg return CIP_DisallowedOnce;
82306f32e7eSjoerg
82406f32e7eSjoerg // Allow disabling temporary destructor inlining with a separate option.
82506f32e7eSjoerg if (CallOpts.IsTemporaryCtorOrDtor &&
82606f32e7eSjoerg !Opts.MayInlineCXXTemporaryDtors)
82706f32e7eSjoerg return CIP_DisallowedOnce;
82806f32e7eSjoerg
82906f32e7eSjoerg // If we did not find the correct this-region, it would be pointless
83006f32e7eSjoerg // to inline the destructor. Instead we will simply invalidate
83106f32e7eSjoerg // the fake temporary target.
83206f32e7eSjoerg if (CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion)
83306f32e7eSjoerg return CIP_DisallowedOnce;
83406f32e7eSjoerg break;
83506f32e7eSjoerg }
836*13fbcb42Sjoerg case CE_CXXDeallocator:
837*13fbcb42Sjoerg LLVM_FALLTHROUGH;
83806f32e7eSjoerg case CE_CXXAllocator:
83906f32e7eSjoerg if (Opts.MayInlineCXXAllocator)
84006f32e7eSjoerg break;
84106f32e7eSjoerg // Do not inline allocators until we model deallocators.
84206f32e7eSjoerg // This is unfortunate, but basically necessary for smart pointers and such.
84306f32e7eSjoerg return CIP_DisallowedAlways;
84406f32e7eSjoerg case CE_ObjCMessage:
84506f32e7eSjoerg if (!Opts.MayInlineObjCMethod)
84606f32e7eSjoerg return CIP_DisallowedAlways;
84706f32e7eSjoerg if (!(Opts.getIPAMode() == IPAK_DynamicDispatch ||
84806f32e7eSjoerg Opts.getIPAMode() == IPAK_DynamicDispatchBifurcate))
84906f32e7eSjoerg return CIP_DisallowedAlways;
85006f32e7eSjoerg break;
85106f32e7eSjoerg }
85206f32e7eSjoerg
85306f32e7eSjoerg return CIP_Allowed;
85406f32e7eSjoerg }
85506f32e7eSjoerg
85606f32e7eSjoerg /// Returns true if the given C++ class contains a member with the given name.
hasMember(const ASTContext & Ctx,const CXXRecordDecl * RD,StringRef Name)85706f32e7eSjoerg static bool hasMember(const ASTContext &Ctx, const CXXRecordDecl *RD,
85806f32e7eSjoerg StringRef Name) {
85906f32e7eSjoerg const IdentifierInfo &II = Ctx.Idents.get(Name);
860*13fbcb42Sjoerg return RD->hasMemberName(Ctx.DeclarationNames.getIdentifier(&II));
86106f32e7eSjoerg }
86206f32e7eSjoerg
86306f32e7eSjoerg /// Returns true if the given C++ class is a container or iterator.
86406f32e7eSjoerg ///
86506f32e7eSjoerg /// Our heuristic for this is whether it contains a method named 'begin()' or a
86606f32e7eSjoerg /// nested type named 'iterator' or 'iterator_category'.
isContainerClass(const ASTContext & Ctx,const CXXRecordDecl * RD)86706f32e7eSjoerg static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) {
86806f32e7eSjoerg return hasMember(Ctx, RD, "begin") ||
86906f32e7eSjoerg hasMember(Ctx, RD, "iterator") ||
87006f32e7eSjoerg hasMember(Ctx, RD, "iterator_category");
87106f32e7eSjoerg }
87206f32e7eSjoerg
87306f32e7eSjoerg /// Returns true if the given function refers to a method of a C++ container
87406f32e7eSjoerg /// or iterator.
87506f32e7eSjoerg ///
87606f32e7eSjoerg /// We generally do a poor job modeling most containers right now, and might
87706f32e7eSjoerg /// prefer not to inline their methods.
isContainerMethod(const ASTContext & Ctx,const FunctionDecl * FD)87806f32e7eSjoerg static bool isContainerMethod(const ASTContext &Ctx,
87906f32e7eSjoerg const FunctionDecl *FD) {
88006f32e7eSjoerg if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
88106f32e7eSjoerg return isContainerClass(Ctx, MD->getParent());
88206f32e7eSjoerg return false;
88306f32e7eSjoerg }
88406f32e7eSjoerg
88506f32e7eSjoerg /// Returns true if the given function is the destructor of a class named
88606f32e7eSjoerg /// "shared_ptr".
isCXXSharedPtrDtor(const FunctionDecl * FD)88706f32e7eSjoerg static bool isCXXSharedPtrDtor(const FunctionDecl *FD) {
88806f32e7eSjoerg const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(FD);
88906f32e7eSjoerg if (!Dtor)
89006f32e7eSjoerg return false;
89106f32e7eSjoerg
89206f32e7eSjoerg const CXXRecordDecl *RD = Dtor->getParent();
89306f32e7eSjoerg if (const IdentifierInfo *II = RD->getDeclName().getAsIdentifierInfo())
89406f32e7eSjoerg if (II->isStr("shared_ptr"))
89506f32e7eSjoerg return true;
89606f32e7eSjoerg
89706f32e7eSjoerg return false;
89806f32e7eSjoerg }
89906f32e7eSjoerg
90006f32e7eSjoerg /// Returns true if the function in \p CalleeADC may be inlined in general.
90106f32e7eSjoerg ///
90206f32e7eSjoerg /// This checks static properties of the function, such as its signature and
90306f32e7eSjoerg /// CFG, to determine whether the analyzer should ever consider inlining it,
90406f32e7eSjoerg /// in any context.
mayInlineDecl(AnalysisDeclContext * CalleeADC) const90506f32e7eSjoerg bool ExprEngine::mayInlineDecl(AnalysisDeclContext *CalleeADC) const {
90606f32e7eSjoerg AnalyzerOptions &Opts = AMgr.getAnalyzerOptions();
90706f32e7eSjoerg // FIXME: Do not inline variadic calls.
90806f32e7eSjoerg if (CallEvent::isVariadic(CalleeADC->getDecl()))
90906f32e7eSjoerg return false;
91006f32e7eSjoerg
91106f32e7eSjoerg // Check certain C++-related inlining policies.
91206f32e7eSjoerg ASTContext &Ctx = CalleeADC->getASTContext();
91306f32e7eSjoerg if (Ctx.getLangOpts().CPlusPlus) {
91406f32e7eSjoerg if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeADC->getDecl())) {
91506f32e7eSjoerg // Conditionally control the inlining of template functions.
91606f32e7eSjoerg if (!Opts.MayInlineTemplateFunctions)
91706f32e7eSjoerg if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
91806f32e7eSjoerg return false;
91906f32e7eSjoerg
92006f32e7eSjoerg // Conditionally control the inlining of C++ standard library functions.
92106f32e7eSjoerg if (!Opts.MayInlineCXXStandardLibrary)
92206f32e7eSjoerg if (Ctx.getSourceManager().isInSystemHeader(FD->getLocation()))
92306f32e7eSjoerg if (AnalysisDeclContext::isInStdNamespace(FD))
92406f32e7eSjoerg return false;
92506f32e7eSjoerg
92606f32e7eSjoerg // Conditionally control the inlining of methods on objects that look
92706f32e7eSjoerg // like C++ containers.
92806f32e7eSjoerg if (!Opts.MayInlineCXXContainerMethods)
92906f32e7eSjoerg if (!AMgr.isInCodeFile(FD->getLocation()))
93006f32e7eSjoerg if (isContainerMethod(Ctx, FD))
93106f32e7eSjoerg return false;
93206f32e7eSjoerg
93306f32e7eSjoerg // Conditionally control the inlining of the destructor of C++ shared_ptr.
93406f32e7eSjoerg // We don't currently do a good job modeling shared_ptr because we can't
93506f32e7eSjoerg // see the reference count, so treating as opaque is probably the best
93606f32e7eSjoerg // idea.
93706f32e7eSjoerg if (!Opts.MayInlineCXXSharedPtrDtor)
93806f32e7eSjoerg if (isCXXSharedPtrDtor(FD))
93906f32e7eSjoerg return false;
94006f32e7eSjoerg }
94106f32e7eSjoerg }
94206f32e7eSjoerg
94306f32e7eSjoerg // It is possible that the CFG cannot be constructed.
94406f32e7eSjoerg // Be safe, and check if the CalleeCFG is valid.
94506f32e7eSjoerg const CFG *CalleeCFG = CalleeADC->getCFG();
94606f32e7eSjoerg if (!CalleeCFG)
94706f32e7eSjoerg return false;
94806f32e7eSjoerg
94906f32e7eSjoerg // Do not inline large functions.
95006f32e7eSjoerg if (isHuge(CalleeADC))
95106f32e7eSjoerg return false;
95206f32e7eSjoerg
95306f32e7eSjoerg // It is possible that the live variables analysis cannot be
95406f32e7eSjoerg // run. If so, bail out.
95506f32e7eSjoerg if (!CalleeADC->getAnalysis<RelaxedLiveVariables>())
95606f32e7eSjoerg return false;
95706f32e7eSjoerg
95806f32e7eSjoerg return true;
95906f32e7eSjoerg }
96006f32e7eSjoerg
shouldInlineCall(const CallEvent & Call,const Decl * D,const ExplodedNode * Pred,const EvalCallOptions & CallOpts)96106f32e7eSjoerg bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
96206f32e7eSjoerg const ExplodedNode *Pred,
96306f32e7eSjoerg const EvalCallOptions &CallOpts) {
96406f32e7eSjoerg if (!D)
96506f32e7eSjoerg return false;
96606f32e7eSjoerg
96706f32e7eSjoerg AnalysisManager &AMgr = getAnalysisManager();
96806f32e7eSjoerg AnalyzerOptions &Opts = AMgr.options;
96906f32e7eSjoerg AnalysisDeclContextManager &ADCMgr = AMgr.getAnalysisDeclContextManager();
97006f32e7eSjoerg AnalysisDeclContext *CalleeADC = ADCMgr.getContext(D);
97106f32e7eSjoerg
97206f32e7eSjoerg // The auto-synthesized bodies are essential to inline as they are
97306f32e7eSjoerg // usually small and commonly used. Note: we should do this check early on to
97406f32e7eSjoerg // ensure we always inline these calls.
97506f32e7eSjoerg if (CalleeADC->isBodyAutosynthesized())
97606f32e7eSjoerg return true;
97706f32e7eSjoerg
97806f32e7eSjoerg if (!AMgr.shouldInlineCall())
97906f32e7eSjoerg return false;
98006f32e7eSjoerg
98106f32e7eSjoerg // Check if this function has been marked as non-inlinable.
98206f32e7eSjoerg Optional<bool> MayInline = Engine.FunctionSummaries->mayInline(D);
98306f32e7eSjoerg if (MayInline.hasValue()) {
98406f32e7eSjoerg if (!MayInline.getValue())
98506f32e7eSjoerg return false;
98606f32e7eSjoerg
98706f32e7eSjoerg } else {
98806f32e7eSjoerg // We haven't actually checked the static properties of this function yet.
98906f32e7eSjoerg // Do that now, and record our decision in the function summaries.
99006f32e7eSjoerg if (mayInlineDecl(CalleeADC)) {
99106f32e7eSjoerg Engine.FunctionSummaries->markMayInline(D);
99206f32e7eSjoerg } else {
99306f32e7eSjoerg Engine.FunctionSummaries->markShouldNotInline(D);
99406f32e7eSjoerg return false;
99506f32e7eSjoerg }
99606f32e7eSjoerg }
99706f32e7eSjoerg
99806f32e7eSjoerg // Check if we should inline a call based on its kind.
99906f32e7eSjoerg // FIXME: this checks both static and dynamic properties of the call, which
100006f32e7eSjoerg // means we're redoing a bit of work that could be cached in the function
100106f32e7eSjoerg // summary.
100206f32e7eSjoerg CallInlinePolicy CIP = mayInlineCallKind(Call, Pred, Opts, CallOpts);
100306f32e7eSjoerg if (CIP != CIP_Allowed) {
100406f32e7eSjoerg if (CIP == CIP_DisallowedAlways) {
100506f32e7eSjoerg assert(!MayInline.hasValue() || MayInline.getValue());
100606f32e7eSjoerg Engine.FunctionSummaries->markShouldNotInline(D);
100706f32e7eSjoerg }
100806f32e7eSjoerg return false;
100906f32e7eSjoerg }
101006f32e7eSjoerg
101106f32e7eSjoerg // Do not inline if recursive or we've reached max stack frame count.
101206f32e7eSjoerg bool IsRecursive = false;
101306f32e7eSjoerg unsigned StackDepth = 0;
101406f32e7eSjoerg examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth);
101506f32e7eSjoerg if ((StackDepth >= Opts.InlineMaxStackDepth) &&
101606f32e7eSjoerg (!isSmall(CalleeADC) || IsRecursive))
101706f32e7eSjoerg return false;
101806f32e7eSjoerg
101906f32e7eSjoerg // Do not inline large functions too many times.
102006f32e7eSjoerg if ((Engine.FunctionSummaries->getNumTimesInlined(D) >
102106f32e7eSjoerg Opts.MaxTimesInlineLarge) &&
102206f32e7eSjoerg isLarge(CalleeADC)) {
102306f32e7eSjoerg NumReachedInlineCountMax++;
102406f32e7eSjoerg return false;
102506f32e7eSjoerg }
102606f32e7eSjoerg
102706f32e7eSjoerg if (HowToInline == Inline_Minimal && (!isSmall(CalleeADC) || IsRecursive))
102806f32e7eSjoerg return false;
102906f32e7eSjoerg
103006f32e7eSjoerg return true;
103106f32e7eSjoerg }
103206f32e7eSjoerg
isTrivialObjectAssignment(const CallEvent & Call)103306f32e7eSjoerg static bool isTrivialObjectAssignment(const CallEvent &Call) {
103406f32e7eSjoerg const CXXInstanceCall *ICall = dyn_cast<CXXInstanceCall>(&Call);
103506f32e7eSjoerg if (!ICall)
103606f32e7eSjoerg return false;
103706f32e7eSjoerg
103806f32e7eSjoerg const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(ICall->getDecl());
103906f32e7eSjoerg if (!MD)
104006f32e7eSjoerg return false;
104106f32e7eSjoerg if (!(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()))
104206f32e7eSjoerg return false;
104306f32e7eSjoerg
104406f32e7eSjoerg return MD->isTrivial();
104506f32e7eSjoerg }
104606f32e7eSjoerg
defaultEvalCall(NodeBuilder & Bldr,ExplodedNode * Pred,const CallEvent & CallTemplate,const EvalCallOptions & CallOpts)104706f32e7eSjoerg void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
104806f32e7eSjoerg const CallEvent &CallTemplate,
104906f32e7eSjoerg const EvalCallOptions &CallOpts) {
105006f32e7eSjoerg // Make sure we have the most recent state attached to the call.
105106f32e7eSjoerg ProgramStateRef State = Pred->getState();
105206f32e7eSjoerg CallEventRef<> Call = CallTemplate.cloneWithState(State);
105306f32e7eSjoerg
105406f32e7eSjoerg // Special-case trivial assignment operators.
105506f32e7eSjoerg if (isTrivialObjectAssignment(*Call)) {
105606f32e7eSjoerg performTrivialCopy(Bldr, Pred, *Call);
105706f32e7eSjoerg return;
105806f32e7eSjoerg }
105906f32e7eSjoerg
106006f32e7eSjoerg // Try to inline the call.
106106f32e7eSjoerg // The origin expression here is just used as a kind of checksum;
106206f32e7eSjoerg // this should still be safe even for CallEvents that don't come from exprs.
106306f32e7eSjoerg const Expr *E = Call->getOriginExpr();
106406f32e7eSjoerg
106506f32e7eSjoerg ProgramStateRef InlinedFailedState = getInlineFailedState(State, E);
106606f32e7eSjoerg if (InlinedFailedState) {
106706f32e7eSjoerg // If we already tried once and failed, make sure we don't retry later.
106806f32e7eSjoerg State = InlinedFailedState;
106906f32e7eSjoerg } else {
107006f32e7eSjoerg RuntimeDefinition RD = Call->getRuntimeDefinition();
107106f32e7eSjoerg const Decl *D = RD.getDecl();
107206f32e7eSjoerg if (shouldInlineCall(*Call, D, Pred, CallOpts)) {
107306f32e7eSjoerg if (RD.mayHaveOtherDefinitions()) {
107406f32e7eSjoerg AnalyzerOptions &Options = getAnalysisManager().options;
107506f32e7eSjoerg
107606f32e7eSjoerg // Explore with and without inlining the call.
107706f32e7eSjoerg if (Options.getIPAMode() == IPAK_DynamicDispatchBifurcate) {
107806f32e7eSjoerg BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred);
107906f32e7eSjoerg return;
108006f32e7eSjoerg }
108106f32e7eSjoerg
108206f32e7eSjoerg // Don't inline if we're not in any dynamic dispatch mode.
108306f32e7eSjoerg if (Options.getIPAMode() != IPAK_DynamicDispatch) {
108406f32e7eSjoerg conservativeEvalCall(*Call, Bldr, Pred, State);
108506f32e7eSjoerg return;
108606f32e7eSjoerg }
108706f32e7eSjoerg }
108806f32e7eSjoerg
108906f32e7eSjoerg // We are not bifurcating and we do have a Decl, so just inline.
109006f32e7eSjoerg if (inlineCall(*Call, D, Bldr, Pred, State))
109106f32e7eSjoerg return;
109206f32e7eSjoerg }
109306f32e7eSjoerg }
109406f32e7eSjoerg
109506f32e7eSjoerg // If we can't inline it, handle the return value and invalidate the regions.
109606f32e7eSjoerg conservativeEvalCall(*Call, Bldr, Pred, State);
109706f32e7eSjoerg }
109806f32e7eSjoerg
BifurcateCall(const MemRegion * BifurReg,const CallEvent & Call,const Decl * D,NodeBuilder & Bldr,ExplodedNode * Pred)109906f32e7eSjoerg void ExprEngine::BifurcateCall(const MemRegion *BifurReg,
110006f32e7eSjoerg const CallEvent &Call, const Decl *D,
110106f32e7eSjoerg NodeBuilder &Bldr, ExplodedNode *Pred) {
110206f32e7eSjoerg assert(BifurReg);
110306f32e7eSjoerg BifurReg = BifurReg->StripCasts();
110406f32e7eSjoerg
110506f32e7eSjoerg // Check if we've performed the split already - note, we only want
110606f32e7eSjoerg // to split the path once per memory region.
110706f32e7eSjoerg ProgramStateRef State = Pred->getState();
110806f32e7eSjoerg const unsigned *BState =
110906f32e7eSjoerg State->get<DynamicDispatchBifurcationMap>(BifurReg);
111006f32e7eSjoerg if (BState) {
111106f32e7eSjoerg // If we are on "inline path", keep inlining if possible.
111206f32e7eSjoerg if (*BState == DynamicDispatchModeInlined)
111306f32e7eSjoerg if (inlineCall(Call, D, Bldr, Pred, State))
111406f32e7eSjoerg return;
111506f32e7eSjoerg // If inline failed, or we are on the path where we assume we
111606f32e7eSjoerg // don't have enough info about the receiver to inline, conjure the
111706f32e7eSjoerg // return value and invalidate the regions.
111806f32e7eSjoerg conservativeEvalCall(Call, Bldr, Pred, State);
111906f32e7eSjoerg return;
112006f32e7eSjoerg }
112106f32e7eSjoerg
112206f32e7eSjoerg // If we got here, this is the first time we process a message to this
112306f32e7eSjoerg // region, so split the path.
112406f32e7eSjoerg ProgramStateRef IState =
112506f32e7eSjoerg State->set<DynamicDispatchBifurcationMap>(BifurReg,
112606f32e7eSjoerg DynamicDispatchModeInlined);
112706f32e7eSjoerg inlineCall(Call, D, Bldr, Pred, IState);
112806f32e7eSjoerg
112906f32e7eSjoerg ProgramStateRef NoIState =
113006f32e7eSjoerg State->set<DynamicDispatchBifurcationMap>(BifurReg,
113106f32e7eSjoerg DynamicDispatchModeConservative);
113206f32e7eSjoerg conservativeEvalCall(Call, Bldr, Pred, NoIState);
113306f32e7eSjoerg
113406f32e7eSjoerg NumOfDynamicDispatchPathSplits++;
113506f32e7eSjoerg }
113606f32e7eSjoerg
VisitReturnStmt(const ReturnStmt * RS,ExplodedNode * Pred,ExplodedNodeSet & Dst)113706f32e7eSjoerg void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
113806f32e7eSjoerg ExplodedNodeSet &Dst) {
113906f32e7eSjoerg ExplodedNodeSet dstPreVisit;
114006f32e7eSjoerg getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this);
114106f32e7eSjoerg
114206f32e7eSjoerg StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
114306f32e7eSjoerg
114406f32e7eSjoerg if (RS->getRetValue()) {
114506f32e7eSjoerg for (ExplodedNodeSet::iterator it = dstPreVisit.begin(),
114606f32e7eSjoerg ei = dstPreVisit.end(); it != ei; ++it) {
114706f32e7eSjoerg B.generateNode(RS, *it, (*it)->getState());
114806f32e7eSjoerg }
114906f32e7eSjoerg }
115006f32e7eSjoerg }
1151