clang 23.0.0git
ExprEngineCallAndReturn.cpp
Go to the documentation of this file.
1//=-- ExprEngineCallAndReturn.cpp - Support for call/return -----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines ExprEngine's support for calls and returns.
10//
11//===----------------------------------------------------------------------===//
12
14#include "clang/AST/Decl.h"
15#include "clang/AST/DeclCXX.h"
23#include "llvm/Support/Casting.h"
24#include "llvm/Support/Compiler.h"
25#include "llvm/Support/SaveAndRestore.h"
26#include <optional>
27
28using namespace clang;
29using namespace ento;
30
31#define DEBUG_TYPE "ExprEngine"
32
34 NumOfDynamicDispatchPathSplits,
35 "The # of times we split the path due to imprecise dynamic dispatch info");
36
37STAT_COUNTER(NumInlinedCalls, "The # of times we inlined a call");
38
39STAT_COUNTER(NumReachedInlineCountMax,
40 "The # of times we reached inline count maximum");
41
43 // Get the entry block in the CFG of the callee.
44 const CFGBlock *Entry = CE.getEntry();
45
46 // Validate the CFG.
47 assert(Entry->empty());
48 assert(Entry->succ_size() == 1);
49
50 // Get the solitary successor.
51 const CFGBlock *Succ = *(Entry->succ_begin());
52
53 // Construct an edge representing the starting location in the callee.
54 BlockEdge Loc(Entry, Succ, CE.getCalleeStackFrame());
55
56 ProgramStateRef state = Pred->getState();
57
58 // Construct a new node, notify checkers that analysis of the function has
59 // begun, and add the resultant nodes to the worklist.
60 bool isNew;
61 ExplodedNode *Node = G.getNode(Loc, state, false, &isNew);
62 Node->addPredecessor(Pred, G);
63 if (isNew) {
64 // FIXME: In the `processBeginOfFunction` callback
65 // `ExprEngine::getCurrStackFrame()` can be different from the
66 // `StackFrame` queried from e.g. the `ExplodedNode`s. I'm not
67 // touching this now because this commit is NFC; but in the future it would
68 // be nice to avoid this inconsistency.
69 ExplodedNodeSet DstBegin;
70 processBeginOfFunction(Node, DstBegin, Loc);
71 Engine.enqueue(DstBegin);
72 }
73}
74
75// Find the last statement on the path to the exploded node and the
76// corresponding Block.
77static std::pair<const Stmt*,
78 const CFGBlock*> getLastStmt(const ExplodedNode *Node) {
79 const Stmt *S = nullptr;
80 const CFGBlock *Blk = nullptr;
81 const StackFrame *SF = Node->getStackFrame();
82
83 // Back up through the ExplodedGraph until we reach a statement node in this
84 // stack frame.
85 while (Node) {
86 const ProgramPoint &PP = Node->getLocation();
87
88 if (PP.getStackFrame() == SF) {
89 if (std::optional<StmtPoint> SP = PP.getAs<StmtPoint>()) {
90 S = SP->getStmt();
91 break;
92 } else if (std::optional<CallExitEnd> CEE = PP.getAs<CallExitEnd>()) {
93 S = CEE->getCalleeStackFrame()->getCallSite();
94 if (S)
95 break;
96
97 // If there is no statement, this is an implicitly-generated call.
98 // We'll walk backwards over it and then continue the loop to find
99 // an actual statement.
100 std::optional<CallEnter> CE;
101 do {
102 Node = Node->getFirstPred();
103 CE = Node->getLocationAs<CallEnter>();
104 } while (!CE ||
105 CE->getCalleeStackFrame() != CEE->getCalleeStackFrame());
106
107 // Continue searching the graph.
108 } else if (std::optional<BlockEdge> BE = PP.getAs<BlockEdge>()) {
109 Blk = BE->getSrc();
110 }
111 } else if (std::optional<CallEnter> CE = PP.getAs<CallEnter>()) {
112 // If we reached the CallEnter for this function, it has no statements.
113 if (CE->getCalleeStackFrame() == SF)
114 break;
115 }
116
117 if (Node->pred_empty())
118 return std::make_pair(nullptr, nullptr);
119
120 Node = *Node->pred_begin();
121 }
122
123 return std::make_pair(S, Blk);
124}
125
126/// Adjusts a return value when the called function's return type does not
127/// match the caller's expression type. This can happen when a dynamic call
128/// is devirtualized, and the overriding method has a covariant (more specific)
129/// return type than the parent's method. For C++ objects, this means we need
130/// to add base casts.
131static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy,
132 StoreManager &StoreMgr) {
133 // For now, the only adjustments we handle apply only to locations.
134 if (!isa<Loc>(V))
135 return V;
136
137 // If the types already match, don't do any unnecessary work.
138 ExpectedTy = ExpectedTy.getCanonicalType();
139 ActualTy = ActualTy.getCanonicalType();
140 if (ExpectedTy == ActualTy)
141 return V;
142
143 // No adjustment is needed between Objective-C pointer types.
144 if (ExpectedTy->isObjCObjectPointerType() &&
145 ActualTy->isObjCObjectPointerType())
146 return V;
147
148 // C++ object pointers may need "derived-to-base" casts.
150 const CXXRecordDecl *ActualClass = ActualTy->getPointeeCXXRecordDecl();
151 if (ExpectedClass && ActualClass) {
152 CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
153 /*DetectVirtual=*/false);
154 if (ActualClass->isDerivedFrom(ExpectedClass, Paths) &&
155 !Paths.isAmbiguous(ActualTy->getCanonicalTypeUnqualified())) {
156 return StoreMgr.evalDerivedToBase(V, Paths.front());
157 }
158 }
159
160 // Unfortunately, Objective-C does not enforce that overridden methods have
161 // covariant return types, so we can't assert that that never happens.
162 // Be safe and return UnknownVal().
163 return UnknownVal();
164}
165
167 ExplodedNodeSet &Dst) {
168 // Find the last statement in the function and the corresponding basic block.
169 const Stmt *LastSt = nullptr;
170 const CFGBlock *Blk = nullptr;
171 std::tie(LastSt, Blk) = getLastStmt(Pred);
172 if (!Blk || !LastSt) {
173 Dst.insert(Pred);
174 return;
175 }
176
177 // Here, we destroy the current stack frame. We use the current function's
178 // entire body as a diagnostic statement, with which the program point
179 // will be associated. However, we only want to use LastStmt as a reference
180 // for what to clean up if it's a ReturnStmt; otherwise, everything is dead.
181 const StackFrame *SF = Pred->getStackFrame();
182 removeDead(Pred, Dst, dyn_cast<ReturnStmt>(LastSt), SF,
185}
186
188 const StackFrame *calleeCtx) {
189 const Decl *RuntimeCallee = calleeCtx->getDecl();
190 const Decl *StaticDecl = Call->getDecl();
191 assert(RuntimeCallee);
192 if (!StaticDecl)
193 return true;
194 return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl();
195}
196
197// Returns the number of elements in the array currently being destructed.
198// If the element count is not found 0 will be returned.
200 const CallEvent &Call, const ProgramStateRef State, SValBuilder &SVB) {
202 "The call event is not a destructor call!");
203
204 const auto &DtorCall = cast<CXXDestructorCall>(Call);
205
206 auto ThisVal = DtorCall.getCXXThisVal();
207
208 if (auto ThisElementRegion = dyn_cast<ElementRegion>(ThisVal.getAsRegion())) {
209 auto ArrayRegion = ThisElementRegion->getAsArrayOffset().getRegion();
210 auto ElementType = ThisElementRegion->getElementType();
211
212 auto ElementCount =
213 getDynamicElementCount(State, ArrayRegion, SVB, ElementType);
214
215 if (!ElementCount.isConstant())
216 return 0;
217
218 return ElementCount.getAsInteger()->getLimitedValue();
219 }
220
221 return 0;
222}
223
224ProgramStateRef ExprEngine::removeStateTraitsUsedForArrayEvaluation(
225 ProgramStateRef State, const CXXConstructExpr *E, const StackFrame *SF) {
226
227 assert(SF && "Stack frame must be provided!");
228
229 if (E) {
230 if (getPendingInitLoop(State, E, SF))
231 State = removePendingInitLoop(State, E, SF);
232
233 if (getIndexOfElementToConstruct(State, E, SF))
234 State = removeIndexOfElementToConstruct(State, E, SF);
235 }
236
237 if (getPendingArrayDestruction(State, SF))
238 State = removePendingArrayDestruction(State, SF);
239
240 return State;
241}
242
243/// The call exit is simulated with a sequence of nodes, which occur between
244/// CallExitBegin and CallExitEnd. The following operations occur between the
245/// two program points:
246/// 1. CallExitBegin (triggers the start of call exit sequence)
247/// 2. Bind the return value
248/// 3. Run Remove dead bindings to clean up the dead symbols from the callee.
249/// 4. CallExitEnd
250/// 5. PostStmt<CallExpr>
251/// Steps 1-3. happen in the callee stack frame; but there is a stack frame
252/// switch and steps 4-5. happen in the caller stack frame.
254 // Step 1 CEBNode was generated before the call.
255 const StackFrame *CalleeSF = CEBNode->getStackFrame();
256
257 const StackFrame *CallerSF = CalleeSF->getParent();
258
259 const Expr *CE = CalleeSF->getCallSite();
260 ProgramStateRef State = CEBNode->getState();
261 // Find the last statement in the function and the corresponding basic block.
262 auto [LastSt, Blk] = getLastStmt(CEBNode);
263
264 const CFGBlock *PrePurgeBlock =
265 isa_and_nonnull<ReturnStmt>(LastSt) ? Blk : &CEBNode->getCFG().getExit();
266 // The first half of this process happens in the callee stack frame:
267 setCurrStackFrameAndBlock(CalleeSF, PrePurgeBlock);
268
269 // Generate a CallEvent /before/ cleaning the State, so that we can get the
270 // correct value for 'this' (if necessary).
272 CallEventRef<> Call = CEMgr.getCaller(CalleeSF, State);
273
274 // Step 2: generate node with bound return value: CEBNode -> BoundRetNode.
275
276 // If this variable is set to 'true' the analyzer will evaluate the call
277 // statement we are about to exit again, instead of continuing the execution
278 // from the statement after the call. This is useful for non-POD type array
279 // construction where the CXXConstructExpr is referenced only once in the CFG,
280 // but we want to evaluate it as many times as many elements the array has.
281 bool ShouldRepeatCall = false;
282
283 if (const auto *DtorDecl =
284 dyn_cast_or_null<CXXDestructorDecl>(Call->getDecl())) {
285 if (auto Idx = getPendingArrayDestruction(State, CallerSF)) {
286 ShouldRepeatCall = *Idx > 0;
287
288 auto ThisVal = svalBuilder.getCXXThis(DtorDecl->getParent(), CalleeSF);
289 State = State->killBinding(ThisVal);
290 }
291 }
292
293 // If the callee returns an expression, bind its value to CallExpr.
294 if (CE) {
295 if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
296 const StackFrame *SF = CEBNode->getStackFrame();
297
298 SVal V = UndefinedVal();
299 if (RS->getRetValue())
300 V = State->getSVal(RS->getRetValue(), SF);
301
302 // Ensure that the return type matches the type of the returned Expr.
303 if (wasDifferentDeclUsedForInlining(Call, CalleeSF)) {
304 QualType ReturnedTy =
306 if (!ReturnedTy.isNull()) {
307 V = adjustReturnValue(V, CE->getType(), ReturnedTy,
309 }
310 }
311
312 State = State->BindExpr(CE, CallerSF, V);
313 }
314
315 // Bind the constructed object value to CXXConstructExpr.
316 if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
318 svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), CalleeSF);
319 SVal ThisV = State->getSVal(This);
320 ThisV = State->getSVal(ThisV.castAs<Loc>());
321 State = State->BindExpr(CCE, CallerSF, ThisV);
322
323 ShouldRepeatCall = shouldRepeatCtorCall(State, CCE, CallerSF);
324 }
325
326 if (const auto *CNE = dyn_cast<CXXNewExpr>(CE)) {
327 // We are currently evaluating a CXXNewAllocator CFGElement. It takes a
328 // while to reach the actual CXXNewExpr element from here, so keep the
329 // region for later use.
330 // Additionally cast the return value of the inlined operator new
331 // (which is of type 'void *') to the correct object type.
332 SVal AllocV = State->getSVal(CNE, CallerSF);
333 AllocV = svalBuilder.evalCast(
334 AllocV, CNE->getType(),
335 getContext().getPointerType(getContext().VoidTy));
336
337 State =
338 addObjectUnderConstruction(State, CNE, CalleeSF->getParent(), AllocV);
339 }
340 }
341
342 if (!ShouldRepeatCall) {
343 State = removeStateTraitsUsedForArrayEvaluation(
344 State, dyn_cast_or_null<CXXConstructExpr>(CE), CallerSF);
345 }
346
347 // Step 3: BoundRetNode -> CleanedNodes
348 // If we can find a statement and a block in the inlined function, run remove
349 // dead bindings before returning from the call. This is important to ensure
350 // that we report the issues such as leaks in the stack frames in which
351 // they occurred.
352 ExplodedNodeSet CleanedNodes;
353 if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) {
354 static SimpleProgramPointTag RetValBind("ExprEngine", "Bind Return Value");
355 auto Loc = isa<ReturnStmt>(LastSt)
356 ? ProgramPoint{PostStmt(LastSt, CalleeSF, &RetValBind)}
357 : ProgramPoint{EpsilonPoint(CalleeSF, /*Data1=*/nullptr,
358 /*Data2=*/nullptr, &RetValBind)};
359
360 ExplodedNode *BoundRetNode = Engine.makeNode(Loc, State, CEBNode);
361 if (!BoundRetNode)
362 return;
363
364 // We call removeDead in the stack frame of the callee.
365 removeDead(BoundRetNode, CleanedNodes, /*ReferenceStmt=*/nullptr, CalleeSF,
366 /*DiagnosticStmt=*/CalleeSF->getAnalysisDeclContext()->getBody(),
368 } else {
369 CleanedNodes.insert(CEBNode);
370 }
371
372 // The second half of this process happens in the caller stack frame. This is
373 // an exception to the general rule that the current StackFrame and Block
374 // stay the same within a single call to dispatchWorkItem.
376 setCurrStackFrameAndBlock(CallerSF, CalleeSF->getCallSiteBlock());
377 SaveAndRestore CBISave(currStmtIdx, CalleeSF->getIndex());
378
379 for (ExplodedNode *N : CleanedNodes) {
380 // Step 4: Generate the CallExitEnd node.
381 // CleanedNodes -> CEENode
382 CallExitEnd Loc(CalleeSF, CallerSF);
383 ProgramStateRef CEEState = (N == CEBNode) ? State : N->getState();
384
385 ExplodedNode *CEENode = Engine.makeNode(Loc, CEEState, N);
386 if (!CEENode)
387 return;
388
389 // Step 5: Perform the post-condition check of the CallExpr and enqueue the
390 // result onto the work list.
391 // CEENode -> Dst -> WorkList
392
393 CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState);
394
395 ExplodedNodeSet DstPostPostCallCallback;
396 getCheckerManager().runCheckersForPostCall(DstPostPostCallCallback, CEENode,
397 *UpdatedCall, *this,
398 /*wasInlined=*/true);
399 ExplodedNodeSet DstPostCall;
400 if (llvm::isa_and_nonnull<CXXNewExpr>(CE)) {
401 for (ExplodedNode *I : DstPostPostCallCallback) {
403 cast<CXXAllocatorCall>(*UpdatedCall), DstPostCall, I, *this,
404 /*wasInlined=*/true);
405 }
406 } else {
407 DstPostCall.insert(DstPostPostCallCallback);
408 }
409
410 ExplodedNodeSet Dst;
411 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {
412 getCheckerManager().runCheckersForPostObjCMessage(Dst, DstPostCall, *Msg,
413 *this,
414 /*wasInlined=*/true);
415 } else if (CE &&
416 !(isa<CXXNewExpr>(CE) && // Called when visiting CXXNewExpr.
417 AMgr.getAnalyzerOptions().MayInlineCXXAllocator)) {
418 getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE,
419 *this, /*wasInlined=*/true);
420 } else {
421 Dst.insert(DstPostCall);
422 }
423
424 // Enqueue the next element in the block.
425 for (ExplodedNode *DstNode : Dst) {
426 unsigned Idx = CalleeSF->getIndex() + (ShouldRepeatCall ? 0 : 1);
427
428 Engine.getWorkList()->enqueue(DstNode, CalleeSF->getCallSiteBlock(), Idx);
429 }
430 }
431}
432
433bool ExprEngine::isSmall(AnalysisDeclContext *ADC) const {
434 // When there are no branches in the function, it means that there's no
435 // exponential complexity introduced by inlining such function.
436 // Such functions also don't trigger various fundamental problems
437 // with our inlining mechanism, such as the problem of
438 // inlined defensive checks. Hence isLinear().
439 const CFG *Cfg = ADC->getCFG();
440 return Cfg->isLinear() || Cfg->size() <= AMgr.options.AlwaysInlineSize;
441}
442
443bool ExprEngine::isLarge(AnalysisDeclContext *ADC) const {
444 const CFG *Cfg = ADC->getCFG();
445 return Cfg->size() >= AMgr.options.MinCFGSizeTreatFunctionsAsLarge;
446}
447
448bool ExprEngine::isHuge(AnalysisDeclContext *ADC) const {
449 const CFG *Cfg = ADC->getCFG();
450 return Cfg->getNumBlockIDs() > AMgr.options.MaxInlinableSize;
451}
452
453void ExprEngine::examineStackFrames(const Decl *D, const StackFrame *SF,
454 bool &IsRecursive, unsigned &StackDepth) {
455 IsRecursive = false;
456 StackDepth = 0;
457
458 while (SF) {
459 const Decl *DI = SF->getDecl();
460
461 // Mark recursive (and mutually recursive) functions and always count
462 // them when measuring the stack depth.
463 if (DI == D) {
464 IsRecursive = true;
465 ++StackDepth;
466 SF = SF->getParent();
467 continue;
468 }
469
470 // Do not count the small functions when determining the stack depth.
471 AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(DI);
472 if (!isSmall(CalleeADC))
473 ++StackDepth;
474 SF = SF->getParent();
475 }
476}
477
478// The GDM component containing the dynamic dispatch bifurcation info. When
479// the exact type of the receiver is not known, we want to explore both paths -
480// one on which we do inline it and the other one on which we don't. This is
481// done to ensure we do not drop coverage.
482// This is the map from the receiver region to a bool, specifying either we
483// consider this region's information precise or not along the given path.
484namespace {
485 enum DynamicDispatchMode {
486 DynamicDispatchModeInlined = 1,
487 DynamicDispatchModeConservative
488 };
489} // end anonymous namespace
490
491REGISTER_MAP_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap,
492 const MemRegion *, unsigned)
493REGISTER_TRAIT_WITH_PROGRAMSTATE(CTUDispatchBifurcation, bool)
494
495void ExprEngine::ctuBifurcate(const CallEvent &Call, const Decl *D,
496 NodeBuilder &Bldr, ExplodedNode *Pred,
497 ProgramStateRef State) {
498 ProgramStateRef ConservativeEvalState = nullptr;
499 if (Call.isForeign() && !isSecondPhaseCTU()) {
500 const auto IK = AMgr.options.getCTUPhase1Inlining();
501 const bool DoInline = IK == CTUPhase1InliningKind::All ||
503 isSmall(AMgr.getAnalysisDeclContext(D)));
504 if (DoInline) {
505 inlineCall(Engine.getWorkList(), Call, D, Bldr, Pred, State);
506 return;
507 }
508 const bool BState = State->get<CTUDispatchBifurcation>();
509 if (!BState) { // This is the first time we see this foreign function.
510 // Enqueue it to be analyzed in the second (ctu) phase.
511 inlineCall(Engine.getCTUWorkList(), Call, D, Bldr, Pred, State);
512 // Conservatively evaluate in the first phase.
513 ConservativeEvalState = State->set<CTUDispatchBifurcation>(true);
514 conservativeEvalCall(Call, Bldr, Pred, ConservativeEvalState);
515 } else {
516 conservativeEvalCall(Call, Bldr, Pred, State);
517 }
518 return;
519 }
520 inlineCall(Engine.getWorkList(), Call, D, Bldr, Pred, State);
521}
522
523void ExprEngine::inlineCall(WorkList *WList, const CallEvent &Call,
524 const Decl *D, NodeBuilder &Bldr,
525 ExplodedNode *Pred, ProgramStateRef State) {
526 assert(D);
527
528 const StackFrame *CallerSF = Pred->getStackFrame();
529 const BlockDataRegion *BlockInvocationData = nullptr;
530 if (Call.getKind() == CE_Block &&
531 !cast<BlockCall>(Call).isConversionFromLambda()) {
532 BlockInvocationData = cast<BlockCall>(Call).getBlockRegion();
533 assert(BlockInvocationData &&
534 "If we have the block definition we should have its region");
535 }
536
537 // This may be NULL, but that's fine.
538 const Expr *CallE = Call.getOriginExpr();
539
540 // Construct a new stack frame for the callee.
541 AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
542 const StackFrame *CalleeSF = CalleeADC->getStackFrame(
543 CallerSF, BlockInvocationData, CallE, getCurrBlock(),
544 getNumVisitedCurrent(), currStmtIdx);
545
546 CallEnter Loc(CallE, CalleeSF, CallerSF);
547
548 // Construct a new state which contains the mapping from actual to
549 // formal arguments.
550 State = State->enterStackFrame(Call, CalleeSF);
551
552 bool isNew;
553 if (ExplodedNode *N = G.getNode(Loc, State, false, &isNew)) {
554 N->addPredecessor(Pred, G);
555 if (isNew)
556 WList->enqueue(N);
557 }
558
559 // If we decided to inline the call, the successor has been manually
560 // added onto the work list so remove it from the node builder.
561 Bldr.takeNodes(Pred);
562
563 NumInlinedCalls++;
564 Engine.FunctionSummaries->bumpNumTimesInlined(D);
565
566 // Do not mark as visited in the 2nd run (CTUWList), so the function will
567 // be visited as top-level, this way we won't loose reports in non-ctu
568 // mode. Considering the case when a function in a foreign TU calls back
569 // into the main TU.
570 // Note, during the 1st run, it doesn't matter if we mark the foreign
571 // functions as visited (or not) because they can never appear as a top level
572 // function in the main TU.
573 if (!isSecondPhaseCTU())
574 // Mark the decl as visited.
575 if (VisitedCallees)
576 VisitedCallees->insert(D);
577}
578
580 const Expr *CallE) {
581 const void *ReplayState = State->get<ReplayWithoutInlining>();
582 if (!ReplayState)
583 return nullptr;
584
585 assert(ReplayState == CallE && "Backtracked to the wrong call.");
586 (void)CallE;
587
588 return State->remove<ReplayWithoutInlining>();
589}
590
592 ExplodedNodeSet &dst) {
593 if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
594 // For instance method operators, make sure the 'this' argument has a
595 // valid region.
596 // FIXME: Why is this only applied for operator calls and not other calls?
597 const Decl *Callee = OCE->getCalleeDecl();
598 if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) {
599 if (MD->isImplicitObjectMemberFunction()) {
600 ProgramStateRef State = Pred->getState();
601 const StackFrame *SF = Pred->getStackFrame();
602 ProgramStateRef NewState =
603 createTemporaryRegionIfNeeded(State, SF, OCE->getArg(0));
604 if (NewState != State) {
605 PreStmt PS(OCE, SF, /*tag=*/nullptr);
606 Pred = Engine.makeNode(PS, NewState, Pred);
607 if (!Pred)
608 return; // Cached out.
609 }
610 }
611 }
612 }
613 // Perform the previsit of the CallExpr.
614 ExplodedNodeSet dstPreVisit;
615 getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this);
616
617 // Get the call in its initial state. We use this as a template to perform
618 // all the checks.
620 CallEventRef<> CallTemplate = CEMgr.getSimpleCall(
621 CE, Pred->getState(), Pred->getStackFrame(), getCFGElementRef());
622
623 // Evaluate the function call. We try each of the checkers
624 // to see if the can evaluate the function call.
625 ExplodedNodeSet dstCallEvaluated;
626 for (ExplodedNode *N : dstPreVisit) {
627 evalCall(dstCallEvaluated, N, *CallTemplate);
628 }
629
630 // Finally, perform the post-condition check of the CallExpr and store
631 // the created nodes in 'Dst'.
632 // Note that if the call was inlined, dstCallEvaluated will be empty.
633 // The post-CallExpr check will occur in processCallExit.
634 getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE,
635 *this);
636}
637
638ProgramStateRef ExprEngine::finishArgumentConstruction(ProgramStateRef State,
639 const CallEvent &Call) {
640 // WARNING: The state attached to 'Call' may be obsolete, do not call any
641 // methods that rely on it!
642 const Expr *E = Call.getOriginExpr();
643 // FIXME: Constructors to placement arguments of operator new
644 // are not supported yet.
645 if (!E || isa<CXXNewExpr>(E))
646 return State;
647
648 const StackFrame *SF = Call.getStackFrame();
649 for (unsigned CallI = 0, CallN = Call.getNumArgs(); CallI != CallN; ++CallI) {
650 unsigned I = Call.getASTArgumentIndex(CallI);
651 if (std::optional<SVal> V = getObjectUnderConstruction(State, {E, I}, SF)) {
652 SVal VV = *V;
653 (void)VV;
655 ->getStackFrame()
656 ->getParent() == SF);
657 State = finishObjectConstruction(State, {E, I}, SF);
658 }
659 }
660
661 return State;
662}
663
664void ExprEngine::finishArgumentConstruction(ExplodedNodeSet &Dst,
665 ExplodedNode *Pred,
666 const CallEvent &Call) {
667 // WARNING: The state attached to 'Call' may be obsolete, do not call any
668 // methods that rely on it!
669 ProgramStateRef State = Pred->getState();
670 ProgramStateRef CleanedState = finishArgumentConstruction(State, Call);
671 if (CleanedState == State) {
672 Dst.insert(Pred);
673 return;
674 }
675
676 const Expr *E = Call.getOriginExpr();
677 const StackFrame *SF = Call.getStackFrame();
678 static SimpleProgramPointTag Tag("ExprEngine",
679 "Finish argument construction");
680 Dst.insert(Engine.makeNode(PreStmt(E, SF, &Tag), CleanedState, Pred));
681}
682
684 const CallEvent &CallTemplate) {
685 // NOTE: CallTemplate is called a "template" because its attached state may
686 // be obsolete (compared to the state of Pred). The state-dependent methods
687 // of CallEvent should be used only after a `cloneWithState` call that
688 // attaches the up-to-date state to this template object.
689
690 // Run any pre-call checks using the generic call interface.
691 ExplodedNodeSet dstPreVisit;
692 getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, CallTemplate,
693 *this);
694
695 // Actually evaluate the function call. We try each of the checkers
696 // to see if the can evaluate the function call, and get a callback at
697 // defaultEvalCall if all of them fail.
698 ExplodedNodeSet dstCallEvaluated;
700 dstCallEvaluated, dstPreVisit, CallTemplate, *this, EvalCallOptions());
701
702 // If there were other constructors called for object-type arguments
703 // of this call, clean them up.
704 ExplodedNodeSet dstArgumentCleanup;
705 for (ExplodedNode *I : dstCallEvaluated)
706 finishArgumentConstruction(dstArgumentCleanup, I, CallTemplate);
707
708 ExplodedNodeSet dstPostCall;
709 getCheckerManager().runCheckersForPostCall(dstPostCall, dstArgumentCleanup,
710 CallTemplate, *this);
711
712 // Escaping symbols conjured during invalidating the regions above.
713 // Note that, for inlined calls the nodes were put back into the worklist,
714 // so we can assume that every node belongs to a conservative call at this
715 // point.
716
717 // Run pointerEscape callback with the newly conjured symbols.
719 for (ExplodedNode *I : dstPostCall) {
720 ProgramStateRef State = I->getState();
721 CallEventRef<> Call = CallTemplate.cloneWithState(State);
722 Escaped.clear();
723 {
724 unsigned Arg = -1;
725 for (const ParmVarDecl *PVD : Call->parameters()) {
726 ++Arg;
727 QualType ParamTy = PVD->getType();
728 if (ParamTy.isNull() ||
729 (!ParamTy->isPointerType() && !ParamTy->isReferenceType()))
730 continue;
731 QualType Pointee = ParamTy->getPointeeType();
732 if (Pointee.isConstQualified() || Pointee->isVoidType())
733 continue;
734 if (const MemRegion *MR = Call->getArgSVal(Arg).getAsRegion())
735 Escaped.emplace_back(loc::MemRegionVal(MR), State->getSVal(MR, Pointee));
736 }
737 }
738
739 State = processPointerEscapedOnBind(State, Escaped, I->getStackFrame(),
741
742 if (State != I->getState())
743 I = Engine.makeNode(I->getLocation(), State, I);
744
745 Dst.insert(I);
746 }
747}
748
750 const StackFrame *SF,
751 ProgramStateRef State) {
752 const Expr *E = Call.getOriginExpr();
753 const ConstCFGElementRef &Elem = Call.getCFGElementRef();
754 if (!E)
755 return State;
756
757 // Some method families have known return values.
758 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
759 switch (Msg->getMethodFamily()) {
760 default:
761 break;
762 case OMF_autorelease:
763 case OMF_retain:
764 case OMF_self: {
765 // These methods return their receivers.
766 return State->BindExpr(E, SF, Msg->getReceiverSVal());
767 }
768 }
769 } else if (const CXXConstructorCall *C = dyn_cast<CXXConstructorCall>(&Call)){
770 SVal ThisV = C->getCXXThisVal();
771 ThisV = State->getSVal(ThisV.castAs<Loc>());
772 return State->BindExpr(E, SF, ThisV);
773 }
774
775 SVal R;
776 QualType ResultTy = Call.getResultType();
777 unsigned Count = getNumVisitedCurrent();
778 if (auto RTC = getCurrentCFGElement().getAs<CFGCXXRecordTypedCall>()) {
779 // Conjure a temporary if the function returns an object by value.
780 SVal Target;
781 assert(RTC->getStmt() == Call.getOriginExpr());
782 EvalCallOptions CallOpts; // FIXME: We won't really need those.
783 std::tie(State, Target) =
784 handleConstructionContext(Call.getOriginExpr(), State, currBldrCtx, SF,
785 RTC->getConstructionContext(), CallOpts);
786 const MemRegion *TargetR = Target.getAsRegion();
787 assert(TargetR);
788 // Invalidate the region so that it didn't look uninitialized. If this is
789 // a field or element constructor, we do not want to invalidate
790 // the whole structure. Pointer escape is meaningless because
791 // the structure is a product of conservative evaluation
792 // and therefore contains nothing interesting at this point.
794 ITraits.setTrait(TargetR,
796 State = State->invalidateRegions(TargetR, Elem, Count, SF,
797 /* CausesPointerEscape=*/false, nullptr,
798 &Call, &ITraits);
799
800 R = State->getSVal(Target.castAs<Loc>(), E->getType());
801 } else {
802 // Conjure a symbol if the return value is unknown.
803
804 // See if we need to conjure a heap pointer instead of
805 // a regular unknown pointer.
806 const auto *CNE = dyn_cast<CXXNewExpr>(E);
807 if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
808 R = svalBuilder.getConjuredHeapSymbolVal(Elem, SF, E->getType(), Count);
809 const MemRegion *MR = R.getAsRegion()->StripCasts();
810
811 // Store the extent of the allocated object(s).
812 SVal ElementCount;
813 if (const Expr *SizeExpr = CNE->getArraySize().value_or(nullptr)) {
814 ElementCount = State->getSVal(SizeExpr, SF);
815 } else {
816 ElementCount = svalBuilder.makeIntVal(1, /*IsUnsigned=*/true);
817 }
818
819 SVal ElementSize = getElementExtent(CNE->getAllocatedType(), svalBuilder);
820
821 SVal Size =
822 svalBuilder.evalBinOp(State, BO_Mul, ElementCount, ElementSize,
823 svalBuilder.getArrayIndexType());
824
825 // FIXME: This line is to prevent a crash. For more details please check
826 // issue #56264.
827 if (Size.isUndef())
828 Size = UnknownVal();
829
830 State = setDynamicExtent(State, MR, Size.castAs<DefinedOrUnknownSVal>());
831 } else {
832 R = svalBuilder.conjureSymbolVal(Elem, SF, ResultTy, Count);
833 }
834 }
835 return State->BindExpr(E, SF, R);
836}
837
838// Conservatively evaluate call by invalidating regions and binding
839// a conjured return value.
840void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
841 ExplodedNode *Pred, ProgramStateRef State) {
842 State = Call.invalidateRegions(getNumVisitedCurrent(), State);
843 State = bindReturnValue(Call, Pred->getStackFrame(), State);
844
845 // And make the result node.
846 static SimpleProgramPointTag PT("ExprEngine", "Conservative eval call");
847 Bldr.generateNode(Call.getProgramPoint(false, &PT), State, Pred);
848}
849
850ExprEngine::CallInlinePolicy
851ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
852 AnalyzerOptions &Opts,
853 const EvalCallOptions &CallOpts) {
854 const StackFrame *CallerSF = Pred->getStackFrame();
855 switch (Call.getKind()) {
856 case CE_Function:
858 case CE_Block:
859 break;
860 case CE_CXXMember:
863 return CIP_DisallowedAlways;
864 break;
865 case CE_CXXConstructor: {
867 return CIP_DisallowedAlways;
868
870
871 const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
872
874 const ConstructionContext *CC = CCE ? CCE->getConstructionContext()
875 : nullptr;
876
877 if (llvm::isa_and_nonnull<NewAllocatedObjectConstructionContext>(CC) &&
878 !Opts.MayInlineCXXAllocator)
879 return CIP_DisallowedOnce;
880
881 if (CallOpts.IsArrayCtorOrDtor) {
882 if (!shouldInlineArrayConstruction(Pred->getState(), CtorExpr, CallerSF))
883 return CIP_DisallowedOnce;
884 }
885
886 // Inlining constructors requires including initializers in the CFG.
887 const AnalysisDeclContext *ADC = CallerSF->getAnalysisDeclContext();
888 assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers");
889 (void)ADC;
890
891 // If the destructor is trivial, it's always safe to inline the constructor.
892 if (Ctor.getDecl()->getParent()->hasTrivialDestructor())
893 break;
894
895 // For other types, only inline constructors if destructor inlining is
896 // also enabled.
898 return CIP_DisallowedAlways;
899
901 // If we don't handle temporary destructors, we shouldn't inline
902 // their constructors.
903 if (CallOpts.IsTemporaryCtorOrDtor &&
904 !Opts.ShouldIncludeTemporaryDtorsInCFG)
905 return CIP_DisallowedOnce;
906
907 // If we did not find the correct this-region, it would be pointless
908 // to inline the constructor. Instead we will simply invalidate
909 // the fake temporary target.
911 return CIP_DisallowedOnce;
912
913 // If the temporary is lifetime-extended by binding it to a reference-type
914 // field within an aggregate, automatic destructors don't work properly.
916 return CIP_DisallowedOnce;
917 }
918
919 break;
920 }
922 // This doesn't really increase the cost of inlining ever, because
923 // the stack frame of the inherited constructor is trivial.
924 return CIP_Allowed;
925 }
926 case CE_CXXDestructor: {
928 return CIP_DisallowedAlways;
929
930 // Inlining destructors requires building the CFG correctly.
931 const AnalysisDeclContext *ADC = CallerSF->getAnalysisDeclContext();
932 assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors");
933 (void)ADC;
934
935 if (CallOpts.IsArrayCtorOrDtor) {
936 if (!shouldInlineArrayDestruction(getElementCountOfArrayBeingDestructed(
937 Call, Pred->getState(), svalBuilder))) {
938 return CIP_DisallowedOnce;
939 }
940 }
941
942 // Allow disabling temporary destructor inlining with a separate option.
943 if (CallOpts.IsTemporaryCtorOrDtor &&
944 !Opts.MayInlineCXXTemporaryDtors)
945 return CIP_DisallowedOnce;
946
947 // If we did not find the correct this-region, it would be pointless
948 // to inline the destructor. Instead we will simply invalidate
949 // the fake temporary target.
951 return CIP_DisallowedOnce;
952 break;
953 }
955 [[fallthrough]];
956 case CE_CXXAllocator:
957 if (Opts.MayInlineCXXAllocator)
958 break;
959 // Do not inline allocators until we model deallocators.
960 // This is unfortunate, but basically necessary for smart pointers and such.
961 return CIP_DisallowedAlways;
962 case CE_ObjCMessage:
963 if (!Opts.MayInlineObjCMethod)
964 return CIP_DisallowedAlways;
965 if (!(Opts.getIPAMode() == IPAK_DynamicDispatch ||
967 return CIP_DisallowedAlways;
968 break;
969 }
970
971 return CIP_Allowed;
972}
973
974/// Returns true if the given C++ class contains a member with the given name.
975static bool hasMember(const ASTContext &Ctx, const CXXRecordDecl *RD,
976 StringRef Name) {
977 const IdentifierInfo &II = Ctx.Idents.get(Name);
978 return RD->hasMemberName(Ctx.DeclarationNames.getIdentifier(&II));
979}
980
981/// Returns true if the given C++ class is a container or iterator.
982///
983/// Our heuristic for this is whether it contains a method named 'begin()' or a
984/// nested type named 'iterator' or 'iterator_category'.
985static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) {
986 return hasMember(Ctx, RD, "begin") ||
987 hasMember(Ctx, RD, "iterator") ||
988 hasMember(Ctx, RD, "iterator_category");
989}
990
991/// Returns true if the given function refers to a method of a C++ container
992/// or iterator.
993///
994/// We generally do a poor job modeling most containers right now, and might
995/// prefer not to inline their methods.
996static bool isContainerMethod(const ASTContext &Ctx,
997 const FunctionDecl *FD) {
998 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
999 return isContainerClass(Ctx, MD->getParent());
1000 return false;
1001}
1002
1003/// Returns true if the given function is the destructor of a class named
1004/// "shared_ptr".
1005static bool isCXXSharedPtrDtor(const FunctionDecl *FD) {
1006 const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(FD);
1007 if (!Dtor)
1008 return false;
1009
1010 const CXXRecordDecl *RD = Dtor->getParent();
1011 if (const IdentifierInfo *II = RD->getDeclName().getAsIdentifierInfo())
1012 if (II->isStr("shared_ptr"))
1013 return true;
1014
1015 return false;
1016}
1017
1018/// Returns true if the function in \p CalleeADC may be inlined in general.
1019///
1020/// This checks static properties of the function, such as its signature and
1021/// CFG, to determine whether the analyzer should ever consider inlining it,
1022/// in any context.
1023bool ExprEngine::mayInlineDecl(AnalysisDeclContext *CalleeADC) const {
1024 AnalyzerOptions &Opts = AMgr.getAnalyzerOptions();
1025 // FIXME: Do not inline variadic calls.
1026 if (CallEvent::isVariadic(CalleeADC->getDecl()))
1027 return false;
1028
1029 // Check certain C++-related inlining policies.
1030 ASTContext &Ctx = CalleeADC->getASTContext();
1031 if (Ctx.getLangOpts().CPlusPlus) {
1032 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeADC->getDecl())) {
1033 // Conditionally control the inlining of template functions.
1034 if (!Opts.MayInlineTemplateFunctions)
1035 if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
1036 return false;
1037
1038 // Conditionally control the inlining of C++ standard library functions.
1039 if (!Opts.MayInlineCXXStandardLibrary)
1040 if (Ctx.getSourceManager().isInSystemHeader(FD->getLocation()))
1042 return false;
1043
1044 // Conditionally control the inlining of methods on objects that look
1045 // like C++ containers.
1046 if (!Opts.MayInlineCXXContainerMethods)
1047 if (!AMgr.isInCodeFile(FD->getLocation()))
1048 if (isContainerMethod(Ctx, FD))
1049 return false;
1050
1051 // Conditionally control the inlining of the destructor of C++ shared_ptr.
1052 // We don't currently do a good job modeling shared_ptr because we can't
1053 // see the reference count, so treating as opaque is probably the best
1054 // idea.
1055 if (!Opts.MayInlineCXXSharedPtrDtor)
1056 if (isCXXSharedPtrDtor(FD))
1057 return false;
1058 }
1059 }
1060
1061 // It is possible that the CFG cannot be constructed.
1062 // Be safe, and check if the CalleeCFG is valid.
1063 const CFG *CalleeCFG = CalleeADC->getCFG();
1064 if (!CalleeCFG)
1065 return false;
1066
1067 // Do not inline large functions.
1068 if (isHuge(CalleeADC))
1069 return false;
1070
1071 // It is possible that the live variables analysis cannot be
1072 // run. If so, bail out.
1073 if (!CalleeADC->getAnalysis<RelaxedLiveVariables>())
1074 return false;
1075
1076 return true;
1077}
1078
1079bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
1080 const ExplodedNode *Pred,
1081 const EvalCallOptions &CallOpts) {
1082 if (!D)
1083 return false;
1084
1085 AnalysisManager &AMgr = getAnalysisManager();
1086 AnalyzerOptions &Opts = AMgr.options;
1087 AnalysisDeclContextManager &ADCMgr = AMgr.getAnalysisDeclContextManager();
1088 AnalysisDeclContext *CalleeADC = ADCMgr.getContext(D);
1089
1090 // The auto-synthesized bodies are essential to inline as they are
1091 // usually small and commonly used. Note: we should do this check early on to
1092 // ensure we always inline these calls.
1093 if (CalleeADC->isBodyAutosynthesized())
1094 return true;
1095
1096 if (!AMgr.shouldInlineCall())
1097 return false;
1098
1099 // Check if this function has been marked as non-inlinable.
1100 std::optional<bool> MayInline = Engine.FunctionSummaries->mayInline(D);
1101 if (MayInline) {
1102 if (!*MayInline)
1103 return false;
1104
1105 } else {
1106 // We haven't actually checked the static properties of this function yet.
1107 // Do that now, and record our decision in the function summaries.
1108 if (mayInlineDecl(CalleeADC)) {
1109 Engine.FunctionSummaries->markMayInline(D);
1110 } else {
1111 Engine.FunctionSummaries->markShouldNotInline(D);
1112 return false;
1113 }
1114 }
1115
1116 // Check if we should inline a call based on its kind.
1117 // FIXME: this checks both static and dynamic properties of the call, which
1118 // means we're redoing a bit of work that could be cached in the function
1119 // summary.
1120 CallInlinePolicy CIP = mayInlineCallKind(Call, Pred, Opts, CallOpts);
1121 if (CIP != CIP_Allowed) {
1122 if (CIP == CIP_DisallowedAlways) {
1123 assert(!MayInline || *MayInline);
1124 Engine.FunctionSummaries->markShouldNotInline(D);
1125 }
1126 return false;
1127 }
1128
1129 // Do not inline if recursive or we've reached max stack frame count.
1130 bool IsRecursive = false;
1131 unsigned StackDepth = 0;
1132 examineStackFrames(D, Pred->getStackFrame(), IsRecursive, StackDepth);
1133 if ((StackDepth >= Opts.InlineMaxStackDepth) &&
1134 (!isSmall(CalleeADC) || IsRecursive))
1135 return false;
1136
1137 // Do not inline large functions too many times.
1138 if ((Engine.FunctionSummaries->getNumTimesInlined(D) >
1139 Opts.MaxTimesInlineLarge) &&
1140 isLarge(CalleeADC)) {
1141 NumReachedInlineCountMax++;
1142 return false;
1143 }
1144
1145 if (HowToInline == Inline_Minimal && (!isSmall(CalleeADC) || IsRecursive))
1146 return false;
1147
1148 return true;
1149}
1150
1151bool ExprEngine::shouldInlineArrayConstruction(const ProgramStateRef State,
1152 const CXXConstructExpr *CE,
1153 const StackFrame *SF) {
1154 if (!CE)
1155 return false;
1156
1157 // FIXME: Handle other arrays types.
1158 if (const auto *CAT = dyn_cast<ConstantArrayType>(CE->getType())) {
1159 unsigned ArrSize = getContext().getConstantArrayElementCount(CAT);
1160
1161 // This might seem conter-intuitive at first glance, but the functions are
1162 // closely related. Reasoning about destructors depends only on the type
1163 // of the expression that initialized the memory region, which is the
1164 // CXXConstructExpr. So to avoid code repetition, the work is delegated
1165 // to the function that reasons about destructor inlining. Also note that
1166 // if the constructors of the array elements are inlined, the destructors
1167 // can also be inlined and if the destructors can be inline, it's safe to
1168 // inline the constructors.
1169 return shouldInlineArrayDestruction(ArrSize);
1170 }
1171
1172 // Check if we're inside an ArrayInitLoopExpr, and it's sufficiently small.
1173 if (auto Size = getPendingInitLoop(State, CE, SF))
1174 return shouldInlineArrayDestruction(*Size);
1175
1176 return false;
1177}
1178
1179bool ExprEngine::shouldInlineArrayDestruction(uint64_t Size) {
1180
1181 uint64_t maxAllowedSize = AMgr.options.maxBlockVisitOnPath;
1182
1183 // Declaring a 0 element array is also possible.
1184 return Size <= maxAllowedSize && Size > 0;
1185}
1186
1187bool ExprEngine::shouldRepeatCtorCall(ProgramStateRef State,
1188 const CXXConstructExpr *E,
1189 const StackFrame *SF) {
1190
1191 if (!E)
1192 return false;
1193
1194 auto Ty = E->getType();
1195
1196 // FIXME: Handle non constant array types
1197 if (const auto *CAT = dyn_cast<ConstantArrayType>(Ty)) {
1199 return Size > getIndexOfElementToConstruct(State, E, SF);
1200 }
1201
1202 if (auto Size = getPendingInitLoop(State, E, SF))
1203 return Size > getIndexOfElementToConstruct(State, E, SF);
1204
1205 return false;
1206}
1207
1209 const CXXInstanceCall *ICall = dyn_cast<CXXInstanceCall>(&Call);
1210 if (!ICall)
1211 return false;
1212
1213 const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(ICall->getDecl());
1214 if (!MD)
1215 return false;
1217 return false;
1218
1219 return MD->isTrivial();
1220}
1221
1223 const CallEvent &Call,
1224 const EvalCallOptions &CallOpts) {
1225 // Make sure we have the most recent state attached to the call.
1226 ProgramStateRef State = Pred->getState();
1227
1228 // Special-case trivial assignment operators.
1230 performTrivialCopy(Bldr, Pred, Call);
1231 return;
1232 }
1233
1234 const Expr *E = Call.getOriginExpr();
1235
1236 ProgramStateRef InlinedFailedState = getInlineFailedState(State, E);
1237 if (InlinedFailedState) {
1238 // If we already tried once and failed, make sure we don't retry later.
1239 State = InlinedFailedState;
1240 } else {
1241 RuntimeDefinition RD = Call.getRuntimeDefinition();
1242 Call.setForeign(RD.isForeign());
1243 const Decl *D = RD.getDecl();
1244 if (shouldInlineCall(Call, D, Pred, CallOpts)) {
1245 if (RD.mayHaveOtherDefinitions()) {
1247
1248 // Explore with and without inlining the call.
1249 if (Options.getIPAMode() == IPAK_DynamicDispatchBifurcate) {
1250 BifurcateCall(RD.getDispatchRegion(), Call, D, Bldr, Pred);
1251 return;
1252 }
1253
1254 // Don't inline if we're not in any dynamic dispatch mode.
1255 if (Options.getIPAMode() != IPAK_DynamicDispatch) {
1256 conservativeEvalCall(Call, Bldr, Pred, State);
1257 return;
1258 }
1259 }
1260 ctuBifurcate(Call, D, Bldr, Pred, State);
1261 return;
1262 }
1263 }
1264
1265 // If we can't inline it, clean up the state traits used only if the function
1266 // is inlined.
1267 State = removeStateTraitsUsedForArrayEvaluation(
1268 State, dyn_cast_or_null<CXXConstructExpr>(E), Call.getStackFrame());
1269
1270 // Also handle the return value and invalidate the regions.
1271 conservativeEvalCall(Call, Bldr, Pred, State);
1272}
1273
1274void ExprEngine::BifurcateCall(const MemRegion *BifurReg,
1275 const CallEvent &Call, const Decl *D,
1276 NodeBuilder &Bldr, ExplodedNode *Pred) {
1277 assert(BifurReg);
1278 BifurReg = BifurReg->StripCasts();
1279
1280 // Check if we've performed the split already - note, we only want
1281 // to split the path once per memory region.
1282 ProgramStateRef State = Pred->getState();
1283 const unsigned *BState =
1284 State->get<DynamicDispatchBifurcationMap>(BifurReg);
1285 if (BState) {
1286 // If we are on "inline path", keep inlining if possible.
1287 if (*BState == DynamicDispatchModeInlined)
1288 ctuBifurcate(Call, D, Bldr, Pred, State);
1289 // If inline failed, or we are on the path where we assume we
1290 // don't have enough info about the receiver to inline, conjure the
1291 // return value and invalidate the regions.
1292 conservativeEvalCall(Call, Bldr, Pred, State);
1293 return;
1294 }
1295
1296 // If we got here, this is the first time we process a message to this
1297 // region, so split the path.
1298 ProgramStateRef IState =
1299 State->set<DynamicDispatchBifurcationMap>(BifurReg,
1300 DynamicDispatchModeInlined);
1301 ctuBifurcate(Call, D, Bldr, Pred, IState);
1302
1303 ProgramStateRef NoIState =
1304 State->set<DynamicDispatchBifurcationMap>(BifurReg,
1305 DynamicDispatchModeConservative);
1306 conservativeEvalCall(Call, Bldr, Pred, NoIState);
1307
1308 NumOfDynamicDispatchPathSplits++;
1309}
1310
1312 ExplodedNodeSet &Dst) {
1313 ExplodedNodeSet dstPreVisit;
1314 getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this);
1315
1316 NodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
1317
1318 if (RS->getRetValue()) {
1319 for (ExplodedNodeSet::iterator it = dstPreVisit.begin(),
1320 ei = dstPreVisit.end(); it != ei; ++it) {
1321 B.generateNode(RS, *it, (*it)->getState());
1322 }
1323 }
1324}
#define V(N, I)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
#define STAT_COUNTER(VARNAME, DESC)
static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD)
Returns true if the given C++ class is a container or iterator.
static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call, const StackFrame *calleeCtx)
static std::pair< const Stmt *, const CFGBlock * > getLastStmt(const ExplodedNode *Node)
static bool isTrivialObjectAssignment(const CallEvent &Call)
static bool isCXXSharedPtrDtor(const FunctionDecl *FD)
Returns true if the given function is the destructor of a class named "shared_ptr".
static bool hasMember(const ASTContext &Ctx, const CXXRecordDecl *RD, StringRef Name)
Returns true if the given C++ class contains a member with the given name.
static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy, StoreManager &StoreMgr)
Adjusts a return value when the called function's return type does not match the caller's expression ...
static bool isContainerMethod(const ASTContext &Ctx, const FunctionDecl *FD)
Returns true if the given function refers to a method of a C++ container or iterator.
static unsigned getElementCountOfArrayBeingDestructed(const CallEvent &Call, const ProgramStateRef State, SValBuilder &SVB)
static ProgramStateRef getInlineFailedState(ProgramStateRef State, const Expr *CallE)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
a trap message and trap category.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
SourceManager & getSourceManager()
Definition ASTContext.h:863
DeclarationNameTable DeclarationNames
Definition ASTContext.h:806
IdentifierTable & Idents
Definition ASTContext.h:802
const LangOptions & getLangOpts() const
Definition ASTContext.h:959
uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const
Return number of constant array elements.
AnalysisDeclContext * getContext(const Decl *D)
AnalysisDeclContext contains the context data for the function, method or block under analysis.
static bool isInStdNamespace(const Decl *D)
ASTContext & getASTContext() const
const StackFrame * getStackFrame(const StackFrame *ParentSF, const void *Data, const Expr *E, const CFGBlock *Blk, unsigned BlockCount, unsigned Index)
Obtain a context of the call stack using its parent context.
CFG::BuildOptions & getCFGBuildOptions()
Stores options for the analyzer from the command line.
bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const
Returns the option controlling which C++ member functions will be considered for inlining.
IPAKind getIPAMode() const
Returns the inter-procedural analysis mode.
CTUPhase1InliningKind getCTUPhase1Inlining() const
unsigned InlineMaxStackDepth
The inlining stack depth limit.
Represents a single basic block in a source-level CFG.
Definition CFG.h:652
bool empty() const
Definition CFG.h:1000
succ_iterator succ_begin()
Definition CFG.h:1037
unsigned succ_size() const
Definition CFG.h:1055
Represents C++ constructor call.
Definition CFG.h:161
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
Definition CFG.h:113
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1271
unsigned size() const
Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...
Definition CFG.h:1469
bool isLinear() const
Returns true if the CFG has no branches.
Definition CFG.cpp:5465
CFGBlock & getExit()
Definition CFG.h:1387
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Definition CFG.h:1464
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
CXXBasePath & front()
bool isAmbiguous(CanQualType BaseType) const
Determine whether the path from the most-derived type to the given base type is ambiguous (i....
Represents a call to a C++ constructor.
Definition ExprCXX.h:1552
CXXConstructionKind getConstructionKind() const
Determine whether this constructor is actually constructing a base class (rather than a complete obje...
Definition ExprCXX.h:1663
Represents a C++ destructor within a class.
Definition DeclCXX.h:2882
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2132
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2271
bool isMoveAssignmentOperator() const
Determine whether this is a move assignment operator.
Definition DeclCXX.cpp:2748
bool isCopyAssignmentOperator() const
Determine whether this is a copy-assignment operator, regardless of whether it was declared implicitl...
Definition DeclCXX.cpp:2727
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool hasTrivialDestructor() const
Determine whether this class has a trivial destructor (C++ [class.dtor]p3)
Definition DeclCXX.h:1372
bool hasMemberName(DeclarationName N) const
Determine whether this class has a member with the given name, possibly in a non-dependent base class...
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
Represents a point when we begin processing an inlined call.
const StackFrame * getCalleeStackFrame() const
const CFGBlock * getEntry() const
Returns the entry block in the CFG for the entered function.
Represents a point when we finish the call exit sequence (for inlined call).
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2946
ConstructionContext's subclasses describe different ways of constructing an object in C++.
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
virtual Decl * getCanonicalDecl()
Retrieves the "canonical" declaration of the given declaration.
Definition DeclBase.h:991
DeclarationName getIdentifier(const IdentifierInfo *ID)
Create a declaration name that is a simple identifier.
IdentifierInfo * getAsIdentifierInfo() const
Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn't...
This is a meta program point, which should be skipped by all the diagnostic reasoning etc.
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2018
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
Definition Decl.h:2369
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:340
Represents a parameter to a function.
Definition Decl.h:1808
const StackFrame * getStackFrame() const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
QualType getCanonicalType() const
Definition TypeBase.h:8492
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition TypeBase.h:8513
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3170
Expr * getRetValue()
Definition Stmt.h:3197
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
It represents a stack frame of the call stack.
unsigned getIndex() const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const Expr * getCallSite() const
const Decl * getDecl() const
const StackFrame * getParent() const
It might return null.
const CFGBlock * getCallSiteBlock() const
Stmt - This represents one statement.
Definition Stmt.h:86
bool isVoidType() const
Definition TypeBase.h:9043
bool isPointerType() const
Definition TypeBase.h:8677
CanQualType getCanonicalTypeUnqualified() const
bool isReferenceType() const
Definition TypeBase.h:8701
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition Type.cpp:1959
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:790
bool isObjCObjectPointerType() const
Definition TypeBase.h:8856
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
Represents a call to a C++ constructor.
Definition CallEvent.h:990
const CXXConstructorDecl * getDecl() const override
Returns the declaration of the function or method that will be called.
Definition CallEvent.h:1021
const CXXConstructExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
Definition CallEvent.h:1017
Represents a non-static C++ member function call, no matter how it is written.
Definition CallEvent.h:686
const FunctionDecl * getDecl() const override
Returns the declaration of the function or method that will be called.
Manages the lifetime of CallEvent objects.
Definition CallEvent.h:1363
CallEventRef getCaller(const StackFrame *CalleeSF, ProgramStateRef State)
Gets an outside caller given a callee context.
CallEventRef getSimpleCall(const CallExpr *E, ProgramStateRef State, const StackFrame *SF, CFGBlock::ConstCFGElementRef ElemRef)
Represents an abstract call to a function or method along a particular path.
Definition CallEvent.h:152
CallEventRef< T > cloneWithState(ProgramStateRef NewState) const
Returns a copy of this CallEvent, but using the given state.
Definition CallEvent.h:1479
static QualType getDeclaredResultType(const Decl *D)
Returns the result type of a function or method declaration.
static bool isVariadic(const Decl *D)
Returns true if the given decl is known to be variadic.
void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng)
Run checkers for pre-visiting function calls (including methods, constructors, destructors etc.
void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &CE, ExprEngine &Eng, const EvalCallOptions &CallOpts)
Run checkers for evaluating a call.
void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng, bool wasInlined=false)
Run checkers for post-visiting obj-c messages.
void runCheckersForPostStmt(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng, bool wasInlined=false)
Run checkers for post-visiting Stmts.
void runCheckersForNewAllocator(const CXXAllocatorCall &Call, ExplodedNodeSet &Dst, ExplodedNode *Pred, ExprEngine &Eng, bool wasInlined=false)
Run checkers between C++ operator new and constructor calls.
void runCheckersForPreStmt(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng)
Run checkers for pre-visiting Stmts.
void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng, bool wasInlined=false)
Run checkers for post-visiting function calls (including methods, constructors, destructors etc.
WorkList * getCTUWorkList() const
Definition CoreEngine.h:162
WorkList * getWorkList() const
Definition CoreEngine.h:161
ExplodedNodeSet is a set of ExplodedNode * elements with the invariant that its elements cannot be nu...
void insert(ExplodedNode *N)
const ProgramStateRef & getState() const
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
std::optional< T > getLocationAs() const &
ExplodedNode * getFirstPred()
const StackFrame * getStackFrame() const
ProgramStateManager & getStateManager()
Definition ExprEngine.h:476
void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out, const Stmt *ReferenceStmt, const StackFrame *SF, const Stmt *DiagnosticStmt=nullptr, ProgramPoint::Kind K=ProgramPoint::PreStmtPurgeDeadSymbolsKind)
Run the analyzer's garbage collection - remove dead symbols and bindings from the state.
void removeDeadOnEndOfFunction(ExplodedNode *Pred, ExplodedNodeSet &Dst)
Remove dead bindings/symbols before exiting a function.
void VisitReturnStmt(const ReturnStmt *R, ExplodedNode *Pred, ExplodedNodeSet &Dst)
VisitReturnStmt - Transfer function logic for return statements.
void processCallEnter(CallEnter CE, ExplodedNode *Pred)
Generate the entry node of the callee.
void processCallExit(ExplodedNode *Pred)
Generate the sequence of nodes that simulate the call exit and the post visit for CallExpr.
CFGElement getCurrentCFGElement()
Return the CFG element corresponding to the worklist element that is currently being processed by Exp...
Definition ExprEngine.h:762
static std::optional< unsigned > getIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E, const StackFrame *SF)
Retrieves which element is being constructed in a non-POD type array.
@ Inline_Minimal
Do minimal inlining of callees.
Definition ExprEngine.h:130
ProgramStateRef bindReturnValue(const CallEvent &Call, const StackFrame *SF, ProgramStateRef State)
Create a new state in which the call return value is binded to the call origin expression.
static std::optional< unsigned > getPendingInitLoop(ProgramStateRef State, const CXXConstructExpr *E, const StackFrame *SF)
Retrieves the size of the array in the pending ArrayInitLoopExpr.
void setCurrStackFrameAndBlock(const StackFrame *SF, const CFGBlock *B)
Definition ExprEngine.h:244
void VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &Dst)
VisitCall - Transfer function for function calls.
ASTContext & getContext() const
getContext - Return the ASTContext associated with this analysis.
Definition ExprEngine.h:214
StoreManager & getStoreManager()
Definition ExprEngine.h:479
void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, const CallEvent &Call)
Evaluate a call, running pre- and post-call checkers and allowing checkers to be responsible for hand...
ConstCFGElementRef getCFGElementRef() const
Definition ExprEngine.h:290
static std::optional< unsigned > getPendingArrayDestruction(ProgramStateRef State, const StackFrame *SF)
Retrieves which element is being destructed in a non-POD type array.
ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State, ArrayRef< std::pair< SVal, SVal > > LocAndVals, const StackFrame *SF, PointerEscapeKind Kind, const CallEvent *Call)
Call PointerEscape callback when a value escapes as a result of bind.
CheckerManager & getCheckerManager() const
Definition ExprEngine.h:223
static std::optional< SVal > getObjectUnderConstruction(ProgramStateRef State, const ConstructionContextItem &Item, const StackFrame *SF)
By looking at a certain item that may be potentially part of an object's ConstructionContext,...
void processBeginOfFunction(ExplodedNode *Pred, ExplodedNodeSet &Dst, const BlockEdge &L)
Called by CoreEngine.
unsigned getNumVisitedCurrent() const
Definition ExprEngine.h:299
void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, const CallEvent &Call, const EvalCallOptions &CallOpts={})
Default implementation of call evaluation.
AnalysisManager & getAnalysisManager()
Definition ExprEngine.h:216
std::pair< ProgramStateRef, SVal > handleConstructionContext(const Expr *E, ProgramStateRef State, const NodeBuilderContext *BldrCtx, const StackFrame *SF, const ConstructionContext *CC, EvalCallOptions &CallOpts, unsigned Idx=0)
A convenient wrapper around computeObjectUnderConstruction and updateObjectsUnderConstruction.
Definition ExprEngine.h:811
const CFGBlock * getCurrBlock() const
Get the 'current' CFGBlock corresponding to the current work item (elementary analysis step handled b...
Definition ExprEngine.h:286
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:97
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
This is the simplest builder which generates nodes in the ExplodedGraph.
Definition CoreEngine.h:265
void takeNodes(const ExplodedNodeSet &S)
Definition CoreEngine.h:330
ExplodedNode * generateNode(const ProgramPoint &PP, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink=false)
Generates a node in the ExplodedGraph.
Represents any expression that calls an Objective-C method.
Definition CallEvent.h:1251
CallEventManager & getCallEventManager()
Information about invalidation for a particular region/symbol.
Definition MemRegion.h:1656
void setTrait(SymbolRef Sym, InvalidationKinds IK)
Defines the runtime definition of the called function.
Definition CallEvent.h:109
const MemRegion * getDispatchRegion()
When other definitions are possible, returns the region whose runtime type determines the method defi...
Definition CallEvent.h:140
bool mayHaveOtherDefinitions()
Check if the definition we have is precise.
Definition CallEvent.h:136
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
QualType getType(const ASTContext &) const
Try to get a reasonable type for the given value.
Definition SVals.cpp:180
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition SVals.h:83
SVal evalDerivedToBase(SVal Derived, const CastExpr *Cast)
Evaluates a chain of derived-to-base casts through the path specified in Cast.
Definition Store.cpp:254
virtual void enqueue(const WorkListUnit &U)=0
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getRegion() const
Get the underlining region.
Definition SVals.h:493
@ PSK_EscapeOutParameters
Escape for a new symbol that was generated into a region that the analyzer cannot follow during a con...
DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB, QualType Ty)
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent)
Set the dynamic extent Extent of the region MR.
@ CE_CXXInheritedConstructor
Definition CallEvent.h:68
@ CE_CXXStaticOperator
Definition CallEvent.h:61
@ CE_CXXDestructor
Definition CallEvent.h:64
@ CE_CXXDeallocator
Definition CallEvent.h:72
@ CE_CXXAllocator
Definition CallEvent.h:71
@ CE_CXXConstructor
Definition CallEvent.h:67
@ CE_CXXMemberOperator
Definition CallEvent.h:63
DefinedOrUnknownSVal getElementExtent(QualType Ty, SValBuilder &SVB)
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
CFGBlock::ConstCFGElementRef ConstCFGElementRef
Definition CFG.h:1248
@ ExpectedClass
@ IPAK_DynamicDispatch
Enable inlining of dynamically dispatched methods.
@ IPAK_DynamicDispatchBifurcate
Enable inlining of dynamically dispatched methods, bifurcate paths when exact type info is unavailabl...
@ CIMK_Destructors
Refers to destructors (implicit or explicit).
@ CIMK_MemberFunctions
Refers to regular member function and operator calls.
@ CIMK_Constructors
Refers to constructors (implicit or explicit).
U cast(CodeGen::Address addr)
Definition Address.h:327
unsigned long uint64_t
Hints for figuring out if a call should be inlined during evalCall().
Definition ExprEngine.h:93
bool IsTemporaryLifetimeExtendedViaAggregate
This call is a constructor for a temporary that is lifetime-extended by binding it to a reference-typ...
Definition ExprEngine.h:108
bool IsTemporaryCtorOrDtor
This call is a constructor or a destructor of a temporary value.
Definition ExprEngine.h:103
bool IsArrayCtorOrDtor
This call is a constructor or a destructor for a single element within an array, a part of array cons...
Definition ExprEngine.h:100
bool IsCtorOrDtorWithImproperlyModeledTargetRegion
This call is a constructor or a destructor for which we do not currently compute the this-region corr...
Definition ExprEngine.h:96
Traits for storing the call processing policy inside GDM.