1//===- ExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ----------===//
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 a meta-engine for path-sensitive dataflow analysis that
10// is built on CoreEngine, but provides the boilerplate to execute transfer
11// functions and build the ExplodedGraph at the expression level.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
16#include "PrettyStackTraceStackFrame.h"
17#include "clang/AST/ASTContext.h"
18#include "clang/AST/Decl.h"
19#include "clang/AST/DeclBase.h"
20#include "clang/AST/DeclCXX.h"
21#include "clang/AST/DeclObjC.h"
22#include "clang/AST/Expr.h"
23#include "clang/AST/ExprCXX.h"
24#include "clang/AST/ExprObjC.h"
25#include "clang/AST/ParentMap.h"
26#include "clang/AST/PrettyPrinter.h"
27#include "clang/AST/Stmt.h"
28#include "clang/AST/StmtCXX.h"
29#include "clang/AST/StmtObjC.h"
30#include "clang/AST/Type.h"
31#include "clang/Analysis/AnalysisDeclContext.h"
32#include "clang/Analysis/CFG.h"
33#include "clang/Analysis/ConstructionContext.h"
34#include "clang/Analysis/ProgramPoint.h"
35#include "clang/Basic/IdentifierTable.h"
36#include "clang/Basic/JsonSupport.h"
37#include "clang/Basic/LLVM.h"
38#include "clang/Basic/LangOptions.h"
39#include "clang/Basic/PrettyStackTrace.h"
40#include "clang/Basic/SourceLocation.h"
41#include "clang/Basic/Specifiers.h"
42#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
43#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
44#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
45#include "clang/StaticAnalyzer/Core/CheckerManager.h"
46#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
47#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
48#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
49#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
50#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
51#include "clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h"
52#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
53#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
54#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
55#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
56#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
57#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
58#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
59#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
60#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
61#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
62#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
63#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
64#include "llvm/ADT/APSInt.h"
65#include "llvm/ADT/DenseMap.h"
66#include "llvm/ADT/ImmutableMap.h"
67#include "llvm/ADT/ImmutableSet.h"
68#include "llvm/ADT/STLExtras.h"
69#include "llvm/ADT/SmallVector.h"
70#include "llvm/Support/Casting.h"
71#include "llvm/Support/Compiler.h"
72#include "llvm/Support/DOTGraphTraits.h"
73#include "llvm/Support/ErrorHandling.h"
74#include "llvm/Support/GraphWriter.h"
75#include "llvm/Support/IOSandbox.h"
76#include "llvm/Support/TimeProfiler.h"
77#include "llvm/Support/raw_ostream.h"
78#include <cassert>
79#include <cstdint>
80#include <memory>
81#include <optional>
82#include <string>
83#include <tuple>
84#include <utility>
85#include <vector>
86
87using namespace clang;
88using namespace ento;
89
90#define DEBUG_TYPE "ExprEngine"
91
92STAT_COUNTER(NumRemoveDeadBindings,
93 "The # of times RemoveDeadBindings is called");
94STAT_COUNTER(
95 NumMaxBlockCountReached,
96 "The # of aborted paths due to reaching the maximum block count in "
97 "a top level function");
98STAT_COUNTER(
99 NumMaxBlockCountReachedInInlined,
100 "The # of aborted paths due to reaching the maximum block count in "
101 "an inlined function");
102STAT_COUNTER(NumTimesRetriedWithoutInlining,
103 "The # of times we re-evaluated a call without inlining");
104
105//===----------------------------------------------------------------------===//
106// Internal program state traits.
107//===----------------------------------------------------------------------===//
108
109namespace {
110
111// When modeling a C++ constructor, for a variety of reasons we need to track
112// the location of the object for the duration of its ConstructionContext.
113// ObjectsUnderConstruction maps statements within the construction context
114// to the object's location, so that on every such statement the location
115// could have been retrieved.
116
117/// ConstructedObjectKey is used for being able to find the path-sensitive
118/// memory region of a freshly constructed object while modeling the AST node
119/// that syntactically represents the object that is being constructed.
120/// Semantics of such nodes may sometimes require access to the region that's
121/// not otherwise present in the program state, or to the very fact that
122/// the construction context was present and contained references to these
123/// AST nodes.
124class ConstructedObjectKey {
125 using ConstructedObjectKeyImpl =
126 std::pair<ConstructionContextItem, const StackFrame *>;
127 const ConstructedObjectKeyImpl Impl;
128
129public:
130 explicit ConstructedObjectKey(const ConstructionContextItem &Item,
131 const StackFrame *SF)
132 : Impl(Item, SF) {}
133
134 const ConstructionContextItem &getItem() const { return Impl.first; }
135 const StackFrame *getStackFrame() const { return Impl.second; }
136
137 ASTContext &getASTContext() const {
138 return getStackFrame()->getDecl()->getASTContext();
139 }
140
141 void printJson(llvm::raw_ostream &Out, PrinterHelper *Helper,
142 PrintingPolicy &PP) const {
143 const Stmt *S = getItem().getStmtOrNull();
144 const CXXCtorInitializer *I = nullptr;
145 if (!S)
146 I = getItem().getCXXCtorInitializer();
147
148 if (S)
149 Out << "\"stmt_id\": " << S->getID(Context: getASTContext());
150 else
151 Out << "\"init_id\": " << I->getID(Context: getASTContext());
152
153 // Kind
154 Out << ", \"kind\": \"" << getItem().getKindAsString()
155 << "\", \"argument_index\": ";
156
157 if (getItem().getKind() == ConstructionContextItem::ArgumentKind)
158 Out << getItem().getIndex();
159 else
160 Out << "null";
161
162 // Pretty-print
163 Out << ", \"pretty\": ";
164
165 if (S) {
166 S->printJson(Out, Helper, Policy: PP, /*AddQuotes=*/true);
167 } else {
168 Out << '\"' << I->getAnyMember()->getDeclName() << '\"';
169 }
170 }
171
172 void Profile(llvm::FoldingSetNodeID &ID) const {
173 ID.Add(x: Impl.first);
174 ID.AddPointer(Ptr: Impl.second);
175 }
176
177 bool operator==(const ConstructedObjectKey &RHS) const {
178 return Impl == RHS.Impl;
179 }
180
181 bool operator<(const ConstructedObjectKey &RHS) const {
182 return Impl < RHS.Impl;
183 }
184};
185} // namespace
186
187typedef llvm::ImmutableMap<ConstructedObjectKey, SVal>
188 ObjectsUnderConstructionMap;
189REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction,
190 ObjectsUnderConstructionMap)
191
192// This trait is responsible for storing the index of the element that is to be
193// constructed in the next iteration. As a result a CXXConstructExpr is only
194// stored if it is array type. Also the index is the index of the continuous
195// memory region, which is important for multi-dimensional arrays. E.g:: int
196// arr[2][2]; assume arr[1][1] will be the next element under construction, so
197// the index is 3.
198typedef llvm::ImmutableMap<
199 std::pair<const CXXConstructExpr *, const StackFrame *>, unsigned>
200 IndexOfElementToConstructMap;
201REGISTER_TRAIT_WITH_PROGRAMSTATE(IndexOfElementToConstruct,
202 IndexOfElementToConstructMap)
203
204// This trait is responsible for holding our pending ArrayInitLoopExprs.
205// It pairs the StackFrame and the initializer CXXConstructExpr with
206// the size of the array that's being copy initialized.
207typedef llvm::ImmutableMap<
208 std::pair<const CXXConstructExpr *, const StackFrame *>, unsigned>
209 PendingInitLoopMap;
210REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingInitLoop, PendingInitLoopMap)
211
212typedef llvm::ImmutableMap<const StackFrame *, unsigned>
213 PendingArrayDestructionMap;
214REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingArrayDestruction,
215 PendingArrayDestructionMap)
216
217//===----------------------------------------------------------------------===//
218// Engine construction and deletion.
219//===----------------------------------------------------------------------===//
220
221static const char* TagProviderName = "ExprEngine";
222
223ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU,
224 AnalysisManager &mgr, SetOfConstDecls *VisitedCalleesIn,
225 FunctionSummariesTy *FS, InliningModes HowToInlineIn)
226 : CTU(CTU), IsCTUEnabled(mgr.getAnalyzerOptions().IsNaiveCTUEnabled),
227 AMgr(mgr), AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
228 Engine(*this, FS, mgr.getAnalyzerOptions()), G(Engine.getGraph()),
229 StateMgr(getContext(), mgr.getStoreManagerCreator(),
230 mgr.getConstraintManagerCreator(), G.getAllocator(), this),
231 SymMgr(StateMgr.getSymbolManager()), MRMgr(StateMgr.getRegionManager()),
232 svalBuilder(StateMgr.getSValBuilder()), ObjCNoRet(mgr.getASTContext()),
233 BR(mgr, *this), VisitedCallees(VisitedCalleesIn),
234 HowToInline(HowToInlineIn) {
235 unsigned TrimInterval = mgr.options.GraphTrimInterval;
236 if (TrimInterval != 0) {
237 // Enable eager node reclamation when constructing the ExplodedGraph.
238 G.enableNodeReclamation(Interval: TrimInterval);
239 }
240}
241
242//===----------------------------------------------------------------------===//
243// Utility methods.
244//===----------------------------------------------------------------------===//
245
246ProgramStateRef ExprEngine::getInitialState(const StackFrame *InitSF) {
247 ProgramStateRef state = StateMgr.getInitialState(InitSF);
248 const Decl *D = InitSF->getDecl();
249
250 // Preconditions.
251 // FIXME: It would be nice if we had a more general mechanism to add
252 // such preconditions. Some day.
253 do {
254 if (const auto *FD = dyn_cast<FunctionDecl>(Val: D)) {
255 // Precondition: the first argument of 'main' is an integer guaranteed
256 // to be > 0.
257 const IdentifierInfo *II = FD->getIdentifier();
258 if (!II || !(II->getName() == "main" && FD->getNumParams() > 0))
259 break;
260
261 const ParmVarDecl *PD = FD->getParamDecl(i: 0);
262 QualType T = PD->getType();
263 const auto *BT = dyn_cast<BuiltinType>(Val&: T);
264 if (!BT || !BT->isInteger())
265 break;
266
267 const MemRegion *R = state->getRegion(D: PD, SF: InitSF);
268 if (!R)
269 break;
270
271 SVal V = state->getSVal(LV: loc::MemRegionVal(R));
272 SVal Constraint_untested = evalBinOp(ST: state, Op: BO_GT, LHS: V,
273 RHS: svalBuilder.makeZeroVal(type: T),
274 T: svalBuilder.getConditionType());
275
276 std::optional<DefinedOrUnknownSVal> Constraint =
277 Constraint_untested.getAs<DefinedOrUnknownSVal>();
278
279 if (!Constraint)
280 break;
281
282 if (ProgramStateRef newState = state->assume(Cond: *Constraint, Assumption: true))
283 state = newState;
284 }
285 break;
286 }
287 while (false);
288
289 if (const auto *MD = dyn_cast<ObjCMethodDecl>(Val: D)) {
290 // Precondition: 'self' is always non-null upon entry to an Objective-C
291 // method.
292 const ImplicitParamDecl *SelfD = MD->getSelfDecl();
293 const MemRegion *R = state->getRegion(D: SelfD, SF: InitSF);
294 SVal V = state->getSVal(LV: loc::MemRegionVal(R));
295
296 if (std::optional<Loc> LV = V.getAs<Loc>()) {
297 // Assume that the pointer value in 'self' is non-null.
298 state = state->assume(Cond: *LV, Assumption: true);
299 assert(state && "'self' cannot be null");
300 }
301 }
302
303 if (const auto *MD = dyn_cast<CXXMethodDecl>(Val: D)) {
304 if (MD->isImplicitObjectMemberFunction()) {
305 // Precondition: 'this' is always non-null upon entry to the
306 // top-level function. This is our starting assumption for
307 // analyzing an "open" program.
308 const StackFrame *SF = InitSF;
309 if (SF->getParent() == nullptr) {
310 loc::MemRegionVal L = svalBuilder.getCXXThis(D: MD, SF);
311 SVal V = state->getSVal(LV: L);
312 if (std::optional<Loc> LV = V.getAs<Loc>()) {
313 state = state->assume(Cond: *LV, Assumption: true);
314 assert(state && "'this' cannot be null");
315 }
316 }
317 }
318 }
319
320 return state;
321}
322
323ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
324 ProgramStateRef State, const StackFrame *SF,
325 const Expr *InitWithAdjustments, const Expr *Result,
326 const SubRegion **OutRegionWithAdjustments) {
327 // FIXME: This function is a hack that works around the quirky AST
328 // we're often having with respect to C++ temporaries. If only we modelled
329 // the actual execution order of statements properly in the CFG,
330 // all the hassle with adjustments would not be necessary,
331 // and perhaps the whole function would be removed.
332 SVal InitValWithAdjustments = State->getSVal(E: InitWithAdjustments, SF);
333 if (!Result) {
334 // If we don't have an explicit result expression, we're in "if needed"
335 // mode. Only create a region if the current value is a NonLoc.
336 if (!isa<NonLoc>(Val: InitValWithAdjustments)) {
337 if (OutRegionWithAdjustments)
338 *OutRegionWithAdjustments = nullptr;
339 return State;
340 }
341 Result = InitWithAdjustments;
342 } else {
343 // We need to create a region no matter what. Make sure we don't try to
344 // stuff a Loc into a non-pointer temporary region.
345 assert(!isa<Loc>(InitValWithAdjustments) ||
346 Loc::isLocType(Result->getType()) ||
347 Result->getType()->isMemberPointerType());
348 }
349
350 ProgramStateManager &StateMgr = State->getStateManager();
351 MemRegionManager &MRMgr = StateMgr.getRegionManager();
352 StoreManager &StoreMgr = StateMgr.getStoreManager();
353
354 // MaterializeTemporaryExpr may appear out of place, after a few field and
355 // base-class accesses have been made to the object, even though semantically
356 // it is the whole object that gets materialized and lifetime-extended.
357 //
358 // For example:
359 //
360 // `-MaterializeTemporaryExpr
361 // `-MemberExpr
362 // `-CXXTemporaryObjectExpr
363 //
364 // instead of the more natural
365 //
366 // `-MemberExpr
367 // `-MaterializeTemporaryExpr
368 // `-CXXTemporaryObjectExpr
369 //
370 // Use the usual methods for obtaining the expression of the base object,
371 // and record the adjustments that we need to make to obtain the sub-object
372 // that the whole expression 'Ex' refers to. This trick is usual,
373 // in the sense that CodeGen takes a similar route.
374
375 SmallVector<const Expr *, 2> CommaLHSs;
376 SmallVector<SubobjectAdjustment, 2> Adjustments;
377
378 const Expr *Init = InitWithAdjustments->skipRValueSubobjectAdjustments(
379 CommaLHS&: CommaLHSs, Adjustments);
380
381 // Take the region for Init, i.e. for the whole object. If we do not remember
382 // the region in which the object originally was constructed, come up with
383 // a new temporary region out of thin air and copy the contents of the object
384 // (which are currently present in the Environment, because Init is an rvalue)
385 // into that region. This is not correct, but it is better than nothing.
386 const TypedValueRegion *TR = nullptr;
387 if (const auto *MT = dyn_cast<MaterializeTemporaryExpr>(Val: Result)) {
388 if (std::optional<SVal> V = getObjectUnderConstruction(State, Item: MT, SF)) {
389 State = finishObjectConstruction(State, Item: MT, SF);
390 State = State->BindExpr(E: Result, SF, V: *V);
391 return State;
392 } else if (const ValueDecl *VD = MT->getExtendingDecl()) {
393 StorageDuration SD = MT->getStorageDuration();
394 assert(SD != SD_FullExpression);
395 // If this object is bound to a reference with static storage duration, we
396 // put it in a different region to prevent "address leakage" warnings.
397 if (SD == SD_Static || SD == SD_Thread) {
398 TR = MRMgr.getCXXStaticLifetimeExtendedObjectRegion(Ex: Init, VD);
399 } else {
400 TR = MRMgr.getCXXLifetimeExtendedObjectRegion(Ex: Init, VD, SF);
401 }
402 } else {
403 assert(MT->getStorageDuration() == SD_FullExpression);
404 TR = MRMgr.getCXXTempObjectRegion(Ex: Init, SF);
405 }
406 } else {
407 TR = MRMgr.getCXXTempObjectRegion(Ex: Init, SF);
408 }
409
410 SVal Reg = loc::MemRegionVal(TR);
411 SVal BaseReg = Reg;
412
413 // Make the necessary adjustments to obtain the sub-object.
414 for (const SubobjectAdjustment &Adj : llvm::reverse(C&: Adjustments)) {
415 switch (Adj.Kind) {
416 case SubobjectAdjustment::DerivedToBaseAdjustment:
417 Reg = StoreMgr.evalDerivedToBase(Derived: Reg, Cast: Adj.DerivedToBase.BasePath);
418 break;
419 case SubobjectAdjustment::FieldAdjustment:
420 Reg = StoreMgr.getLValueField(D: Adj.Field, Base: Reg);
421 break;
422 case SubobjectAdjustment::MemberPointerAdjustment:
423 // FIXME: Unimplemented.
424 State = State->invalidateRegions(Values: Reg, Elem: getCFGElementRef(),
425 BlockCount: getNumVisitedCurrent(), SF, CausesPointerEscape: true,
426 IS: nullptr, Call: nullptr, ITraits: nullptr);
427 return State;
428 }
429 }
430
431 // What remains is to copy the value of the object to the new region.
432 // FIXME: In other words, what we should always do is copy value of the
433 // Init expression (which corresponds to the bigger object) to the whole
434 // temporary region TR. However, this value is often no longer present
435 // in the Environment. If it has disappeared, we instead invalidate TR.
436 // Still, what we can do is assign the value of expression Ex (which
437 // corresponds to the sub-object) to the TR's sub-region Reg. At least,
438 // values inside Reg would be correct.
439 SVal InitVal = State->getSVal(E: Init, SF);
440 if (InitVal.isUnknown()) {
441 InitVal = getSValBuilder().conjureSymbolVal(
442 elem: getCFGElementRef(), SF, type: Init->getType(), visitCount: getNumVisitedCurrent());
443 State = State->bindLoc(location: BaseReg.castAs<Loc>(), V: InitVal, SF, notifyChanges: false);
444
445 // Then we'd need to take the value that certainly exists and bind it
446 // over.
447 if (InitValWithAdjustments.isUnknown()) {
448 // Try to recover some path sensitivity in case we couldn't
449 // compute the value.
450 InitValWithAdjustments = getSValBuilder().conjureSymbolVal(
451 elem: getCFGElementRef(), SF, type: InitWithAdjustments->getType(),
452 visitCount: getNumVisitedCurrent());
453 }
454 State =
455 State->bindLoc(location: Reg.castAs<Loc>(), V: InitValWithAdjustments, SF, notifyChanges: false);
456 } else {
457 State = State->bindLoc(location: BaseReg.castAs<Loc>(), V: InitVal, SF, notifyChanges: false);
458 }
459
460 // The result expression would now point to the correct sub-region of the
461 // newly created temporary region. Do this last in order to getSVal of Init
462 // correctly in case (Result == Init).
463 if (Result->isGLValue()) {
464 State = State->BindExpr(E: Result, SF, V: Reg);
465 } else {
466 State = State->BindExpr(E: Result, SF, V: InitValWithAdjustments);
467 }
468
469 // Notify checkers once for two bindLoc()s.
470 State = processRegionChange(state: State, MR: TR, SF);
471
472 if (OutRegionWithAdjustments)
473 *OutRegionWithAdjustments = cast<SubRegion>(Val: Reg.getAsRegion());
474 return State;
475}
476
477ProgramStateRef
478ExprEngine::setIndexOfElementToConstruct(ProgramStateRef State,
479 const CXXConstructExpr *E,
480 const StackFrame *SF, unsigned Idx) {
481 auto Key = std::make_pair(x&: E, y&: SF);
482
483 assert(!State->contains<IndexOfElementToConstruct>(Key) || Idx > 0);
484
485 return State->set<IndexOfElementToConstruct>(K: Key, E: Idx);
486}
487
488std::optional<unsigned>
489ExprEngine::getPendingInitLoop(ProgramStateRef State, const CXXConstructExpr *E,
490 const StackFrame *SF) {
491 const unsigned *V = State->get<PendingInitLoop>(key: {E, SF});
492 return V ? std::make_optional(t: *V) : std::nullopt;
493}
494
495ProgramStateRef ExprEngine::removePendingInitLoop(ProgramStateRef State,
496 const CXXConstructExpr *E,
497 const StackFrame *SF) {
498 auto Key = std::make_pair(x&: E, y&: SF);
499
500 assert(E && State->contains<PendingInitLoop>(Key));
501 return State->remove<PendingInitLoop>(K: Key);
502}
503
504ProgramStateRef ExprEngine::setPendingInitLoop(ProgramStateRef State,
505 const CXXConstructExpr *E,
506 const StackFrame *SF,
507 unsigned Size) {
508 auto Key = std::make_pair(x&: E, y&: SF);
509
510 assert(!State->contains<PendingInitLoop>(Key) && Size > 0);
511
512 return State->set<PendingInitLoop>(K: Key, E: Size);
513}
514
515std::optional<unsigned> ExprEngine::getIndexOfElementToConstruct(
516 ProgramStateRef State, const CXXConstructExpr *E, const StackFrame *SF) {
517 const unsigned *V = State->get<IndexOfElementToConstruct>(key: {E, SF});
518 return V ? std::make_optional(t: *V) : std::nullopt;
519}
520
521ProgramStateRef ExprEngine::removeIndexOfElementToConstruct(
522 ProgramStateRef State, const CXXConstructExpr *E, const StackFrame *SF) {
523 auto Key = std::make_pair(x&: E, y&: SF);
524
525 assert(E && State->contains<IndexOfElementToConstruct>(Key));
526 return State->remove<IndexOfElementToConstruct>(K: Key);
527}
528
529std::optional<unsigned>
530ExprEngine::getPendingArrayDestruction(ProgramStateRef State,
531 const StackFrame *SF) {
532 assert(SF && "StackFrame shouldn't be null!");
533
534 const unsigned *V = State->get<PendingArrayDestruction>(key: SF);
535 return V ? std::make_optional(t: *V) : std::nullopt;
536}
537
538ProgramStateRef ExprEngine::setPendingArrayDestruction(ProgramStateRef State,
539 const StackFrame *SF,
540 unsigned Idx) {
541 assert(SF && "StackFrame shouldn't be null!");
542 return State->set<PendingArrayDestruction>(K: SF, E: Idx);
543}
544
545ProgramStateRef
546ExprEngine::removePendingArrayDestruction(ProgramStateRef State,
547 const StackFrame *SF) {
548 assert(SF && "StackFrame shouldn't be null!");
549 assert(State->contains<PendingArrayDestruction>(SF));
550 return State->remove<PendingArrayDestruction>(K: SF);
551}
552
553ProgramStateRef
554ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
555 const ConstructionContextItem &Item,
556 const StackFrame *SF, SVal V) {
557 ConstructedObjectKey Key(Item, SF);
558
559 const Expr *Init = nullptr;
560
561 if (auto DS = dyn_cast_or_null<DeclStmt>(Val: Item.getStmtOrNull())) {
562 if (auto VD = dyn_cast_or_null<VarDecl>(Val: DS->getSingleDecl()))
563 Init = VD->getInit();
564 }
565
566 if (auto LE = dyn_cast_or_null<LambdaExpr>(Val: Item.getStmtOrNull()))
567 Init = *(LE->capture_init_begin() + Item.getIndex());
568
569 if (!Init && !Item.getStmtOrNull())
570 Init = Item.getCXXCtorInitializer()->getInit();
571
572 // In an ArrayInitLoopExpr the real initializer is returned by
573 // getSubExpr(). Note that AILEs can be nested in case of
574 // multidimesnional arrays.
575 if (const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Val: Init))
576 Init = extractElementInitializerFromNestedAILE(AILE);
577
578 // FIXME: Currently the state might already contain the marker due to
579 // incorrect handling of temporaries bound to default parameters.
580 // The state will already contain the marker if we construct elements
581 // in an array, as we visit the same statement multiple times before
582 // the array declaration. The marker is removed when we exit the
583 // constructor call.
584 assert((!State->get<ObjectsUnderConstruction>(Key) ||
585 Key.getItem().getKind() ==
586 ConstructionContextItem::TemporaryDestructorKind ||
587 State->contains<IndexOfElementToConstruct>(
588 {dyn_cast_or_null<CXXConstructExpr>(Init), SF})) &&
589 "The object is already marked as `UnderConstruction`, when it's not "
590 "supposed to!");
591 return State->set<ObjectsUnderConstruction>(K: Key, E: V);
592}
593
594std::optional<SVal>
595ExprEngine::getObjectUnderConstruction(ProgramStateRef State,
596 const ConstructionContextItem &Item,
597 const StackFrame *SF) {
598 ConstructedObjectKey Key(Item, SF);
599 const SVal *V = State->get<ObjectsUnderConstruction>(key: Key);
600 return V ? std::make_optional(t: *V) : std::nullopt;
601}
602
603ProgramStateRef
604ExprEngine::finishObjectConstruction(ProgramStateRef State,
605 const ConstructionContextItem &Item,
606 const StackFrame *SF) {
607 ConstructedObjectKey Key(Item, SF);
608 assert(State->contains<ObjectsUnderConstruction>(Key));
609 return State->remove<ObjectsUnderConstruction>(K: Key);
610}
611
612ProgramStateRef ExprEngine::elideDestructor(ProgramStateRef State,
613 const CXXBindTemporaryExpr *BTE,
614 const StackFrame *SF) {
615 ConstructedObjectKey Key({BTE, /*IsElided=*/true}, SF);
616 // FIXME: Currently the state might already contain the marker due to
617 // incorrect handling of temporaries bound to default parameters.
618 return State->set<ObjectsUnderConstruction>(K: Key, E: UnknownVal());
619}
620
621ProgramStateRef
622ExprEngine::cleanupElidedDestructor(ProgramStateRef State,
623 const CXXBindTemporaryExpr *BTE,
624 const StackFrame *SF) {
625 ConstructedObjectKey Key({BTE, /*IsElided=*/true}, SF);
626 assert(State->contains<ObjectsUnderConstruction>(Key));
627 return State->remove<ObjectsUnderConstruction>(K: Key);
628}
629
630bool ExprEngine::isDestructorElided(ProgramStateRef State,
631 const CXXBindTemporaryExpr *BTE,
632 const StackFrame *SF) {
633 ConstructedObjectKey Key({BTE, /*IsElided=*/true}, SF);
634 return State->contains<ObjectsUnderConstruction>(key: Key);
635}
636
637bool ExprEngine::areAllObjectsFullyConstructed(ProgramStateRef State,
638 const StackFrame *FromSF,
639 const StackFrame *ToSF) {
640 const StackFrame *SF = FromSF;
641 while (SF != ToSF) {
642 assert(SF && "ToSF must be a parent of FromSF!");
643 for (auto I : State->get<ObjectsUnderConstruction>())
644 if (I.first.getStackFrame() == SF)
645 return false;
646
647 SF = SF->getParent();
648 }
649 return true;
650}
651
652//===----------------------------------------------------------------------===//
653// Top-level transfer function logic (Dispatcher).
654//===----------------------------------------------------------------------===//
655
656/// evalAssume - Called by ConstraintManager. Used to call checker-specific
657/// logic for handling assumptions on symbolic values.
658ProgramStateRef ExprEngine::processAssume(ProgramStateRef state,
659 SVal cond, bool assumption) {
660 return getCheckerManager().runCheckersForEvalAssume(state, Cond: cond, Assumption: assumption);
661}
662
663ProgramStateRef ExprEngine::processRegionChanges(
664 ProgramStateRef state, const InvalidatedSymbols *invalidated,
665 ArrayRef<const MemRegion *> Explicits, ArrayRef<const MemRegion *> Regions,
666 const StackFrame *SF, const CallEvent *Call) {
667 return getCheckerManager().runCheckersForRegionChanges(
668 state, invalidated, ExplicitRegions: Explicits, Regions, SF, Call);
669}
670
671static void
672printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State,
673 const char *NL, const StackFrame *SF,
674 unsigned int Space = 0, bool IsDot = false) {
675 PrintingPolicy PP =
676 SF->getAnalysisDeclContext()->getASTContext().getPrintingPolicy();
677
678 ++Space;
679 bool HasItem = false;
680
681 // Store the last key.
682 const ConstructedObjectKey *LastKey = nullptr;
683 for (const auto &I : State->get<ObjectsUnderConstruction>()) {
684 const ConstructedObjectKey &Key = I.first;
685 if (Key.getStackFrame() != SF)
686 continue;
687
688 if (!HasItem) {
689 Out << '[' << NL;
690 HasItem = true;
691 }
692
693 LastKey = &Key;
694 }
695
696 for (const auto &I : State->get<ObjectsUnderConstruction>()) {
697 const ConstructedObjectKey &Key = I.first;
698 SVal Value = I.second;
699 if (Key.getStackFrame() != SF)
700 continue;
701
702 Indent(Out, Space, IsDot) << "{ ";
703 Key.printJson(Out, Helper: nullptr, PP);
704 Out << ", \"value\": \"" << Value << "\" }";
705
706 if (&Key != LastKey)
707 Out << ',';
708 Out << NL;
709 }
710
711 if (HasItem)
712 Indent(Out, Space: --Space, IsDot) << ']'; // End of "location_context".
713 else {
714 Out << "null ";
715 }
716}
717
718static void printIndicesOfElementsToConstructJson(
719 raw_ostream &Out, ProgramStateRef State, const char *NL,
720 const StackFrame *SF, unsigned int Space = 0, bool IsDot = false) {
721 using KeyT = std::pair<const Expr *, const StackFrame *>;
722
723 const auto &Context = SF->getAnalysisDeclContext()->getASTContext();
724 PrintingPolicy PP = Context.getPrintingPolicy();
725
726 ++Space;
727 bool HasItem = false;
728
729 // Store the last key.
730 KeyT LastKey;
731 for (const auto &I : State->get<IndexOfElementToConstruct>()) {
732 const KeyT &Key = I.first;
733 if (Key.second != SF)
734 continue;
735
736 if (!HasItem) {
737 Out << '[' << NL;
738 HasItem = true;
739 }
740
741 LastKey = Key;
742 }
743
744 for (const auto &I : State->get<IndexOfElementToConstruct>()) {
745 const KeyT &Key = I.first;
746 unsigned Value = I.second;
747 if (Key.second != SF)
748 continue;
749
750 Indent(Out, Space, IsDot) << "{ ";
751
752 // Expr
753 const Expr *E = Key.first;
754 Out << "\"stmt_id\": " << E->getID(Context);
755
756 // Kind
757 Out << ", \"kind\": null";
758
759 // Pretty-print
760 Out << ", \"pretty\": ";
761 Out << "\"" << E->getStmtClassName() << ' '
762 << E->getSourceRange().printToString(SM: Context.getSourceManager()) << " '"
763 << QualType::getAsString(split: E->getType().split(), Policy: PP);
764 Out << "'\"";
765
766 Out << ", \"value\": \"Current index: " << Value - 1 << "\" }";
767
768 if (Key != LastKey)
769 Out << ',';
770 Out << NL;
771 }
772
773 if (HasItem)
774 Indent(Out, Space: --Space, IsDot) << ']'; // End of "location_context".
775 else {
776 Out << "null ";
777 }
778}
779
780static void printPendingInitLoopJson(raw_ostream &Out, ProgramStateRef State,
781 const char *NL, const StackFrame *SF,
782 unsigned int Space = 0,
783 bool IsDot = false) {
784 using KeyT = std::pair<const CXXConstructExpr *, const StackFrame *>;
785
786 const auto &Context = SF->getAnalysisDeclContext()->getASTContext();
787 PrintingPolicy PP = Context.getPrintingPolicy();
788
789 ++Space;
790 bool HasItem = false;
791
792 // Store the last key.
793 KeyT LastKey;
794 for (const auto &I : State->get<PendingInitLoop>()) {
795 const KeyT &Key = I.first;
796 if (Key.second != SF)
797 continue;
798
799 if (!HasItem) {
800 Out << '[' << NL;
801 HasItem = true;
802 }
803
804 LastKey = Key;
805 }
806
807 for (const auto &I : State->get<PendingInitLoop>()) {
808 const KeyT &Key = I.first;
809 unsigned Value = I.second;
810 if (Key.second != SF)
811 continue;
812
813 Indent(Out, Space, IsDot) << "{ ";
814
815 const CXXConstructExpr *E = Key.first;
816 Out << "\"stmt_id\": " << E->getID(Context);
817
818 Out << ", \"kind\": null";
819 Out << ", \"pretty\": ";
820 Out << '\"' << E->getStmtClassName() << ' '
821 << E->getSourceRange().printToString(SM: Context.getSourceManager()) << " '"
822 << QualType::getAsString(split: E->getType().split(), Policy: PP);
823 Out << "'\"";
824
825 Out << ", \"value\": \"Flattened size: " << Value << "\"}";
826
827 if (Key != LastKey)
828 Out << ',';
829 Out << NL;
830 }
831
832 if (HasItem)
833 Indent(Out, Space: --Space, IsDot) << ']'; // End of "location_context".
834 else {
835 Out << "null ";
836 }
837}
838
839static void
840printPendingArrayDestructionsJson(raw_ostream &Out, ProgramStateRef State,
841 const char *NL, const StackFrame *SF,
842 unsigned int Space = 0, bool IsDot = false) {
843 using KeyT = const StackFrame *;
844
845 ++Space;
846 bool HasItem = false;
847
848 // Store the last key.
849 KeyT LastKey = nullptr;
850 for (const auto &I : State->get<PendingArrayDestruction>()) {
851 const KeyT &Key = I.first;
852 if (Key != SF)
853 continue;
854
855 if (!HasItem) {
856 Out << '[' << NL;
857 HasItem = true;
858 }
859
860 LastKey = Key;
861 }
862
863 for (const auto &I : State->get<PendingArrayDestruction>()) {
864 const KeyT &Key = I.first;
865 if (Key != SF)
866 continue;
867
868 Indent(Out, Space, IsDot) << "{ ";
869
870 Out << "\"stmt_id\": null";
871 Out << ", \"kind\": null";
872 Out << ", \"pretty\": \"Current index: \"";
873 Out << ", \"value\": \"" << I.second << "\" }";
874
875 if (Key != LastKey)
876 Out << ',';
877 Out << NL;
878 }
879
880 if (HasItem)
881 Indent(Out, Space: --Space, IsDot) << ']'; // End of "location_context".
882 else {
883 Out << "null ";
884 }
885}
886
887/// A helper function to generalize program state trait printing.
888/// The function invokes Printer as 'Printer(Out, State, NL, SF, Space, IsDot,
889/// std::forward<Args>(args)...)'. \n One possible type for Printer is
890/// 'void()(raw_ostream &, ProgramStateRef, const char *, const StackFrame *,
891/// unsigned int, bool, ...)' \n \param Trait The state trait to be printed.
892/// \param Printer A void function that prints Trait.
893/// \param Args An additional parameter pack that is passed to Print upon
894/// invocation.
895template <typename Trait, typename Printer, typename... Args>
896static void printStateTraitWithStackFrameJson(
897 raw_ostream &Out, ProgramStateRef State, const StackFrame *SF,
898 const char *NL, unsigned int Space, bool IsDot,
899 const char *jsonPropertyName, Printer printer, Args &&...args) {
900
901 using RequiredType =
902 void (*)(raw_ostream &, ProgramStateRef, const char *, const StackFrame *,
903 unsigned int, bool, Args &&...);
904
905 // Try to do as much compile time checking as possible.
906 // FIXME: check for invocable instead of function?
907 static_assert(std::is_function_v<std::remove_pointer_t<Printer>>,
908 "Printer is not a function!");
909 static_assert(std::is_convertible_v<Printer, RequiredType>,
910 "Printer doesn't have the required type!");
911
912 if (SF && !State->get<Trait>().isEmpty()) {
913 Indent(Out, Space, IsDot) << '\"' << jsonPropertyName << "\": ";
914 ++Space;
915 Out << '[' << NL;
916 SF->printJson(Out, NL, Space, IsDot, printMoreInfoPerStackFrame: [&](const StackFrame *SF) {
917 printer(Out, State, NL, SF, Space, IsDot, std::forward<Args>(args)...);
918 });
919
920 --Space;
921 Indent(Out, Space, IsDot) << "]," << NL; // End of "jsonPropertyName".
922 }
923}
924
925void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State,
926 const StackFrame *SF, const char *NL,
927 unsigned int Space, bool IsDot) const {
928
929 printStateTraitWithStackFrameJson<ObjectsUnderConstruction>(
930 Out, State, SF, NL, Space, IsDot, jsonPropertyName: "constructing_objects",
931 printer: printObjectsUnderConstructionJson);
932 printStateTraitWithStackFrameJson<IndexOfElementToConstruct>(
933 Out, State, SF, NL, Space, IsDot, jsonPropertyName: "index_of_element",
934 printer: printIndicesOfElementsToConstructJson);
935 printStateTraitWithStackFrameJson<PendingInitLoop>(
936 Out, State, SF, NL, Space, IsDot, jsonPropertyName: "pending_init_loops",
937 printer: printPendingInitLoopJson);
938 printStateTraitWithStackFrameJson<PendingArrayDestruction>(
939 Out, State, SF, NL, Space, IsDot, jsonPropertyName: "pending_destructors",
940 printer: printPendingArrayDestructionsJson);
941
942 getCheckerManager().runCheckersForPrintStateJson(Out, State, NL, Space,
943 IsDot);
944}
945
946void ExprEngine::processEndWorklist() {
947 // This prints the name of the top-level function if we crash.
948 PrettyStackTraceStackFrame CrashInfo(getRootStackFrame());
949 getCheckerManager().runCheckersForEndAnalysis(G, BR, Eng&: *this);
950}
951
952void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
953 unsigned StmtIdx) {
954 currStmtIdx = StmtIdx;
955
956 switch (E.getKind()) {
957 case CFGElement::Statement:
958 case CFGElement::Constructor:
959 case CFGElement::CXXRecordTypedCall:
960 ProcessStmt(S: E.castAs<CFGStmt>().getStmt(), Pred);
961 return;
962 case CFGElement::Initializer:
963 ProcessInitializer(I: E.castAs<CFGInitializer>(), Pred);
964 return;
965 case CFGElement::NewAllocator:
966 ProcessNewAllocator(NE: E.castAs<CFGNewAllocator>().getAllocatorExpr(),
967 Pred);
968 return;
969 case CFGElement::AutomaticObjectDtor:
970 case CFGElement::DeleteDtor:
971 case CFGElement::BaseDtor:
972 case CFGElement::MemberDtor:
973 case CFGElement::TemporaryDtor:
974 ProcessImplicitDtor(D: E.castAs<CFGImplicitDtor>(), Pred);
975 return;
976 case CFGElement::LoopExit:
977 ProcessLoopExit(S: E.castAs<CFGLoopExit>().getLoopStmt(), Pred);
978 return;
979 case CFGElement::LifetimeEnds:
980 ProcessLifetimeEnd(S: E.castAs<CFGLifetimeEnds>().getTriggerStmt(),
981 D: E.castAs<CFGLifetimeEnds>().getVarDecl(), Pred);
982 return;
983 case CFGElement::CleanupFunction:
984 case CFGElement::FullExprCleanup:
985 case CFGElement::ScopeBegin:
986 case CFGElement::ScopeEnd:
987 return;
988 }
989}
990
991static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, const Stmt *S,
992 const ExplodedNode *Pred,
993 const StackFrame *SF) {
994 // Are we never purging state values?
995 if (AMgr.options.AnalysisPurgeOpt == PurgeNone)
996 return false;
997
998 // Is this the beginning of a basic block?
999 if (Pred->getLocation().getAs<BlockEntrance>())
1000 return true;
1001
1002 // Is this on a non-expression?
1003 if (!isa<Expr>(Val: S))
1004 return true;
1005
1006 // Run before processing a call.
1007 if (CallEvent::isCallStmt(S))
1008 return true;
1009
1010 // Is this an expression that is consumed by another expression? If so,
1011 // postpone cleaning out the state.
1012 ParentMap &PM = SF->getAnalysisDeclContext()->getParentMap();
1013 return !PM.isConsumedExpr(E: cast<Expr>(Val: S));
1014}
1015
1016void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
1017 const Stmt *ReferenceStmt, const StackFrame *SF,
1018 const Stmt *DiagnosticStmt, ProgramPoint::Kind K) {
1019 llvm::TimeTraceScope TimeScope("ExprEngine::removeDead");
1020 assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
1021 ReferenceStmt == nullptr || isa<ReturnStmt>(ReferenceStmt))
1022 && "PostStmt is not generally supported by the SymbolReaper yet");
1023 assert(SF && "Must pass the current (or expiring) StackFrame");
1024
1025 if (!DiagnosticStmt) {
1026 DiagnosticStmt = ReferenceStmt;
1027 assert(DiagnosticStmt && "Required for clearing a StackFrame");
1028 }
1029
1030 NumRemoveDeadBindings++;
1031 ProgramStateRef CleanedState = Pred->getState();
1032
1033 // SF is the stack frame being destroyed, but SymbolReaper wants a
1034 // stack frame that is still live. (If this is the top-level stack
1035 // frame, this will be null.)
1036 if (!ReferenceStmt) {
1037 assert(K == ProgramPoint::PostStmtPurgeDeadSymbolsKind &&
1038 "Use PostStmtPurgeDeadSymbolsKind for clearing a StackFrame");
1039 SF = SF->getParent();
1040 }
1041
1042 SymbolReaper SymReaper(SF, ReferenceStmt, SymMgr, getStoreManager());
1043
1044 for (auto I : CleanedState->get<ObjectsUnderConstruction>()) {
1045 if (SymbolRef Sym = I.second.getAsSymbol())
1046 SymReaper.markLive(sym: Sym);
1047 if (const MemRegion *MR = I.second.getAsRegion())
1048 SymReaper.markLive(region: MR);
1049 }
1050
1051 getCheckerManager().runCheckersForLiveSymbols(state: CleanedState, SymReaper);
1052
1053 // Create a state in which dead bindings are removed from the environment
1054 // and the store. TODO: The function should just return new env and store,
1055 // not a new state.
1056 CleanedState = StateMgr.removeDeadBindingsFromEnvironmentAndStore(
1057 St: CleanedState, SF, SymReaper);
1058
1059 // Process any special transfer function for dead symbols.
1060 // Call checkers with the non-cleaned state so that they could query the
1061 // values of the soon to be dead symbols.
1062 ExplodedNodeSet CheckedSet;
1063 getCheckerManager().runCheckersForDeadSymbols(Dst&: CheckedSet, Src: Pred, SymReaper,
1064 S: DiagnosticStmt, Eng&: *this, K);
1065
1066 // Extend lifetime of symbols used for dynamic extent while the parent region
1067 // is live. In this way size information about memory allocations is not lost
1068 // if the region remains live.
1069 markAllDynamicExtentLive(State: CleanedState, SymReaper);
1070
1071 // For each node in CheckedSet, generate CleanedNodes that have the
1072 // environment, the store, and the constraints cleaned up but have the
1073 // user-supplied states as the predecessors.
1074 for (const auto I : CheckedSet) {
1075 ProgramStateRef CheckerState = I->getState();
1076
1077 // The constraint manager has not been cleaned up yet, so clean up now.
1078 CheckerState =
1079 getConstraintManager().removeDeadBindings(state: CheckerState, SymReaper);
1080
1081 assert(StateMgr.haveEqualEnvironments(CheckerState, Pred->getState()) &&
1082 "Checkers are not allowed to modify the Environment as a part of "
1083 "checkDeadSymbols processing.");
1084 assert(StateMgr.haveEqualStores(CheckerState, Pred->getState()) &&
1085 "Checkers are not allowed to modify the Store as a part of "
1086 "checkDeadSymbols processing.");
1087
1088 // Create a state based on CleanedState with CheckerState GDM and
1089 // generate a transition to that state.
1090 ProgramStateRef CleanedCheckerSt =
1091 StateMgr.getPersistentStateWithGDM(FromState: CleanedState, GDMState: CheckerState);
1092 const ProgramPoint &L = ProgramPoint::getProgramPoint(
1093 S: DiagnosticStmt, K, SF: I->getStackFrame(), tag: cleanupNodeTag());
1094 Out.insert(N: Engine.makeNode(Loc: L, State: CleanedCheckerSt, Pred: I));
1095 }
1096}
1097
1098const ProgramPointTag *ExprEngine::cleanupNodeTag() {
1099 static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node");
1100 return &cleanupTag;
1101}
1102
1103void ExprEngine::ProcessStmt(const Stmt *currStmt, ExplodedNode *Pred) {
1104 // Reclaim any unnecessary nodes in the ExplodedGraph.
1105 G.reclaimRecentlyAllocatedNodes();
1106
1107 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1108 currStmt->getBeginLoc(),
1109 "Error evaluating statement");
1110
1111 // Remove dead bindings and symbols.
1112 ExplodedNodeSet CleanedStates;
1113 if (shouldRemoveDeadBindings(AMgr, S: currStmt, Pred, SF: Pred->getStackFrame())) {
1114 removeDead(Pred, Out&: CleanedStates, ReferenceStmt: currStmt, SF: Pred->getStackFrame());
1115 } else
1116 CleanedStates.insert(N: Pred);
1117
1118 // Visit the statement.
1119 ExplodedNodeSet Dst;
1120 for (const auto I : CleanedStates) {
1121 ExplodedNodeSet DstI;
1122 // Visit the statement.
1123 Visit(S: currStmt, Pred: I, Dst&: DstI);
1124 Dst.insert(S: DstI);
1125 }
1126
1127 // Enqueue the new nodes onto the work list.
1128 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1129}
1130
1131void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
1132 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1133 S->getBeginLoc(),
1134 "Error evaluating end of the loop");
1135 ProgramStateRef NewState = Pred->getState();
1136
1137 if(AMgr.options.ShouldUnrollLoops)
1138 NewState = processLoopEnd(LoopStmt: S, State: NewState);
1139
1140 LoopExit PP(S, Pred->getStackFrame());
1141 ExplodedNode *N = Engine.makeNode(Loc: PP, State: NewState, Pred);
1142 if (N && !N->isSink())
1143 Engine.enqueueStmtNode(N, Block: getCurrBlock(), Idx: currStmtIdx);
1144}
1145
1146void ExprEngine::ProcessLifetimeEnd(const Stmt *S, const VarDecl *D,
1147 ExplodedNode *Pred) {
1148 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1149 S->getBeginLoc(),
1150 "Error evaluating end of a lifetime");
1151 LifetimeEnd PP(S, D, Pred->getStackFrame());
1152 ExplodedNode *Src = Engine.makeNode(Loc: PP, State: Pred->getState(), Pred);
1153
1154 ExplodedNodeSet Dst;
1155 getCheckerManager().runCheckersForLifetimeEnd(Dst, Src, Decl: D, Eng&: *this);
1156 Engine.enqueueStmtNodes(Set&: Dst, Block: currBldrCtx->getBlock(), Idx: currStmtIdx);
1157}
1158
1159void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
1160 ExplodedNode *Pred) {
1161 const CXXCtorInitializer *BMI = CFGInit.getInitializer();
1162 const Expr *Init = BMI->getInit()->IgnoreImplicit();
1163 const StackFrame *SF = Pred->getStackFrame();
1164
1165 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1166 BMI->getSourceLocation(),
1167 "Error evaluating initializer");
1168
1169 // We don't clean up dead bindings here.
1170 const auto *decl = cast<CXXConstructorDecl>(Val: SF->getDecl());
1171
1172 ProgramStateRef State = Pred->getState();
1173 SVal thisVal = State->getSVal(LV: svalBuilder.getCXXThis(D: decl, SF));
1174
1175 ExplodedNodeSet Tmp;
1176 SVal FieldLoc;
1177
1178 // Evaluate the initializer, if necessary
1179 if (BMI->isAnyMemberInitializer()) {
1180 // Constructors build the object directly in the field,
1181 // but non-objects must be copied in from the initializer.
1182 if (getObjectUnderConstruction(State, Item: BMI, SF)) {
1183 // The field was directly constructed, so there is no need to bind.
1184 // But we still need to stop tracking the object under construction.
1185 State = finishObjectConstruction(State, Item: BMI, SF);
1186 PostStore PS(Init, SF, /*Loc*/ nullptr, /*tag*/ nullptr);
1187 Tmp.insert(N: Engine.makeNode(Loc: PS, State, Pred));
1188 } else {
1189 const ValueDecl *Field;
1190 if (BMI->isIndirectMemberInitializer()) {
1191 Field = BMI->getIndirectMember();
1192 FieldLoc = State->getLValue(decl: BMI->getIndirectMember(), Base: thisVal);
1193 } else {
1194 Field = BMI->getMember();
1195 FieldLoc = State->getLValue(decl: BMI->getMember(), Base: thisVal);
1196 }
1197
1198 SVal InitVal;
1199 if (Field->getType()->isArrayType()) {
1200 // Handle arrays of trivial type. We can represent this with a
1201 // primitive load/copy from the base array region.
1202 const ArraySubscriptExpr *ASE;
1203 while ((ASE = dyn_cast<ArraySubscriptExpr>(Val: Init)))
1204 Init = ASE->getBase()->IgnoreImplicit();
1205
1206 InitVal = State->getSVal(E: Init, SF);
1207
1208 // If we fail to get the value for some reason, use a symbolic value.
1209 if (InitVal.isUnknownOrUndef()) {
1210 SValBuilder &SVB = getSValBuilder();
1211 InitVal = SVB.conjureSymbolVal(
1212 elem: getCFGElementRef(), SF, type: Field->getType(), visitCount: getNumVisitedCurrent());
1213 }
1214 } else {
1215 InitVal = State->getSVal(E: BMI->getInit(), SF);
1216 }
1217
1218 PostInitializer PP(BMI, FieldLoc.getAsRegion(), SF);
1219 evalBind(Dst&: Tmp, StoreE: Init, Pred, location: FieldLoc, Val: InitVal, /*isInit=*/AtDeclInit: true, PP: &PP);
1220 }
1221 } else if (BMI->isBaseInitializer() && isa<InitListExpr>(Val: Init)) {
1222 // When the base class is initialized with an initialization list and the
1223 // base class does not have a ctor, there will not be a CXXConstructExpr to
1224 // initialize the base region. Hence, we need to make the bind for it.
1225 SVal BaseLoc = getStoreManager().evalDerivedToBase(
1226 Derived: thisVal, DerivedPtrType: QualType(BMI->getBaseClass(), 0), IsVirtual: BMI->isBaseVirtual());
1227 SVal InitVal = State->getSVal(E: Init, SF);
1228 evalBind(Dst&: Tmp, StoreE: Init, Pred, location: BaseLoc, Val: InitVal, /*isInit=*/AtDeclInit: true);
1229 } else {
1230 assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
1231 Tmp.insert(N: Pred);
1232 // We already did all the work when visiting the CXXConstructExpr.
1233 }
1234
1235 // Construct PostInitializer nodes whether the state changed or not,
1236 // so that the diagnostics don't get confused.
1237 PostInitializer PP(BMI, FieldLoc.getAsRegion(), SF);
1238
1239 ExplodedNodeSet Dst;
1240 for (ExplodedNode *Pred : Tmp)
1241 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1242 // Enqueue the new nodes onto the work list.
1243 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1244}
1245
1246std::pair<ProgramStateRef, uint64_t>
1247ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State,
1248 const MemRegion *Region,
1249 const QualType &ElementTy,
1250 const StackFrame *SF,
1251 SVal *ElementCountVal) {
1252 assert(Region != nullptr && "Not-null region expected");
1253
1254 QualType Ty = ElementTy.getDesugaredType(Context: getContext());
1255 while (const auto *NTy = dyn_cast<ArrayType>(Val&: Ty))
1256 Ty = NTy->getElementType().getDesugaredType(Context: getContext());
1257
1258 auto ElementCount = getDynamicElementCount(State, MR: Region, SVB&: svalBuilder, Ty);
1259
1260 if (ElementCountVal)
1261 *ElementCountVal = ElementCount;
1262
1263 // Note: the destructors are called in reverse order.
1264 unsigned Idx = 0;
1265 if (auto OptionalIdx = getPendingArrayDestruction(State, SF)) {
1266 Idx = *OptionalIdx;
1267 } else {
1268 // The element count is either unknown, or an SVal that's not an integer.
1269 if (!ElementCount.isConstant())
1270 return {State, 0};
1271
1272 Idx = ElementCount.getAsInteger()->getLimitedValue();
1273 }
1274
1275 if (Idx == 0)
1276 return {State, 0};
1277
1278 --Idx;
1279
1280 return {setPendingArrayDestruction(State, SF, Idx), Idx};
1281}
1282
1283void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
1284 ExplodedNode *Pred) {
1285 ExplodedNodeSet Dst;
1286 switch (D.getKind()) {
1287 case CFGElement::AutomaticObjectDtor:
1288 ProcessAutomaticObjDtor(D: D.castAs<CFGAutomaticObjDtor>(), Pred, Dst);
1289 break;
1290 case CFGElement::BaseDtor:
1291 ProcessBaseDtor(D: D.castAs<CFGBaseDtor>(), Pred, Dst);
1292 break;
1293 case CFGElement::MemberDtor:
1294 ProcessMemberDtor(D: D.castAs<CFGMemberDtor>(), Pred, Dst);
1295 break;
1296 case CFGElement::TemporaryDtor:
1297 ProcessTemporaryDtor(D: D.castAs<CFGTemporaryDtor>(), Pred, Dst);
1298 break;
1299 case CFGElement::DeleteDtor:
1300 ProcessDeleteDtor(D: D.castAs<CFGDeleteDtor>(), Pred, Dst);
1301 break;
1302 default:
1303 llvm_unreachable("Unexpected dtor kind.");
1304 }
1305
1306 // Enqueue the new nodes onto the work list.
1307 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1308}
1309
1310void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
1311 ExplodedNode *Pred) {
1312 ExplodedNodeSet Dst;
1313 AnalysisManager &AMgr = getAnalysisManager();
1314 AnalyzerOptions &Opts = AMgr.options;
1315 // TODO: We're not evaluating allocators for all cases just yet as
1316 // we're not handling the return value correctly, which causes false
1317 // positives when the alpha.cplusplus.NewDeleteLeaks check is on.
1318 if (Opts.MayInlineCXXAllocator)
1319 VisitCXXNewAllocatorCall(CNE: NE, Pred, Dst);
1320 else {
1321 const StackFrame *SF = Pred->getStackFrame();
1322 PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), SF,
1323 getCFGElementRef());
1324 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1325 }
1326 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1327}
1328
1329void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
1330 ExplodedNode *Pred,
1331 ExplodedNodeSet &Dst) {
1332 const auto *DtorDecl = Dtor.getDestructorDecl(astContext&: getContext());
1333 const VarDecl *varDecl = Dtor.getVarDecl();
1334 QualType varType = varDecl->getType();
1335
1336 ProgramStateRef state = Pred->getState();
1337 const StackFrame *SF = Pred->getStackFrame();
1338
1339 SVal dest = state->getLValue(VD: varDecl, SF);
1340 const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion();
1341
1342 if (varType->isReferenceType()) {
1343 const MemRegion *ValueRegion = state->getSVal(R: Region).getAsRegion();
1344 if (!ValueRegion) {
1345 // FIXME: This should not happen. The language guarantees a presence
1346 // of a valid initializer here, so the reference shall not be undefined.
1347 // It seems that we're calling destructors over variables that
1348 // were not initialized yet.
1349 return;
1350 }
1351 Region = ValueRegion->getBaseRegion();
1352 varType = cast<TypedValueRegion>(Val: Region)->getValueType();
1353 }
1354
1355 unsigned Idx = 0;
1356 if (isa<ArrayType>(Val: varType)) {
1357 SVal ElementCount;
1358 std::tie(args&: state, args&: Idx) = prepareStateForArrayDestruction(
1359 State: state, Region, ElementTy: varType, SF, ElementCountVal: &ElementCount);
1360
1361 if (ElementCount.isConstant()) {
1362 uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
1363 assert(ArrayLength &&
1364 "An automatic dtor for a 0 length array shouldn't be triggered!");
1365
1366 // Still handle this case if we don't have assertions enabled.
1367 if (!ArrayLength) {
1368 static SimpleProgramPointTag PT(
1369 "ExprEngine", "Skipping automatic 0 length array destruction, "
1370 "which shouldn't be in the CFG.");
1371 PostImplicitCall PP(DtorDecl, varDecl->getLocation(), SF,
1372 getCFGElementRef(), &PT);
1373 Engine.makeNode(Loc: PP, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
1374 return;
1375 }
1376 }
1377 }
1378
1379 EvalCallOptions CallOpts;
1380 Region = makeElementRegion(State: state, LValue: loc::MemRegionVal(Region), Ty&: varType,
1381 IsArray&: CallOpts.IsArrayCtorOrDtor, Idx)
1382 .getAsRegion();
1383
1384 static SimpleProgramPointTag PT("ExprEngine",
1385 "Prepare for object destruction");
1386 PreImplicitCall PP(DtorDecl, varDecl->getLocation(), SF, getCFGElementRef(),
1387 &PT);
1388 Pred = Engine.makeNode(Loc: PP, State: state, Pred);
1389
1390 if (!Pred)
1391 return;
1392
1393 VisitCXXDestructor(ObjectType: varType, Dest: Region, S: Dtor.getTriggerStmt(),
1394 /*IsBase=*/IsBaseDtor: false, Pred, Dst, Options&: CallOpts);
1395}
1396
1397void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
1398 ExplodedNode *Pred,
1399 ExplodedNodeSet &Dst) {
1400 ProgramStateRef State = Pred->getState();
1401 const StackFrame *SF = Pred->getStackFrame();
1402 const CXXDeleteExpr *DE = Dtor.getDeleteExpr();
1403 const Expr *Arg = DE->getArgument();
1404 QualType DTy = DE->getDestroyedType();
1405 SVal ArgVal = State->getSVal(E: Arg, SF);
1406
1407 // If the argument to delete is known to be a null value,
1408 // don't run destructor.
1409 if (State->isNull(V: ArgVal).isConstrainedTrue()) {
1410 QualType BTy = getContext().getBaseElementType(QT: DTy);
1411 const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl();
1412 const CXXDestructorDecl *Dtor = RD->getDestructor();
1413
1414 PostImplicitCall PP(Dtor, DE->getBeginLoc(), SF, getCFGElementRef());
1415 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1416 return;
1417 }
1418
1419 auto getDtorDecl = [](const QualType &DTy) {
1420 const CXXRecordDecl *RD = DTy->getAsCXXRecordDecl();
1421 return RD->getDestructor();
1422 };
1423
1424 unsigned Idx = 0;
1425 EvalCallOptions CallOpts;
1426 const MemRegion *ArgR = ArgVal.getAsRegion();
1427
1428 if (DE->isArrayForm()) {
1429 CallOpts.IsArrayCtorOrDtor = true;
1430 // Yes, it may even be a multi-dimensional array.
1431 while (const auto *AT = getContext().getAsArrayType(T: DTy))
1432 DTy = AT->getElementType();
1433
1434 if (ArgR) {
1435 SVal ElementCount;
1436 std::tie(args&: State, args&: Idx) =
1437 prepareStateForArrayDestruction(State, Region: ArgR, ElementTy: DTy, SF, ElementCountVal: &ElementCount);
1438
1439 // If we're about to destruct a 0 length array, don't run any of the
1440 // destructors.
1441 if (ElementCount.isConstant() &&
1442 ElementCount.getAsInteger()->getLimitedValue() == 0) {
1443
1444 static SimpleProgramPointTag PT(
1445 "ExprEngine", "Skipping 0 length array delete destruction");
1446 PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), SF,
1447 getCFGElementRef(), &PT);
1448 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1449 return;
1450 }
1451
1452 ArgR = State->getLValue(ElementType: DTy, Idx: svalBuilder.makeArrayIndex(idx: Idx), Base: ArgVal)
1453 .getAsRegion();
1454 }
1455 }
1456
1457 static SimpleProgramPointTag PT("ExprEngine",
1458 "Prepare for object destruction");
1459 PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), SF,
1460 getCFGElementRef(), &PT);
1461 Pred = Engine.makeNode(Loc: PP, State, Pred);
1462
1463 if (!Pred)
1464 return;
1465
1466 VisitCXXDestructor(ObjectType: DTy, Dest: ArgR, S: DE, /*IsBase=*/IsBaseDtor: false, Pred, Dst, Options&: CallOpts);
1467}
1468
1469void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
1470 ExplodedNode *Pred, ExplodedNodeSet &Dst) {
1471 const StackFrame *SF = Pred->getStackFrame();
1472
1473 const auto *CurDtor = cast<CXXDestructorDecl>(Val: SF->getDecl());
1474 Loc ThisPtr = getSValBuilder().getCXXThis(D: CurDtor, SF);
1475 SVal ThisVal = Pred->getState()->getSVal(LV: ThisPtr);
1476
1477 // Create the base object region.
1478 const CXXBaseSpecifier *Base = D.getBaseSpecifier();
1479 QualType BaseTy = Base->getType();
1480 SVal BaseVal = getStoreManager().evalDerivedToBase(Derived: ThisVal, DerivedPtrType: BaseTy,
1481 IsVirtual: Base->isVirtual());
1482
1483 EvalCallOptions CallOpts;
1484 VisitCXXDestructor(ObjectType: BaseTy, Dest: BaseVal.getAsRegion(), S: CurDtor->getBody(),
1485 /*IsBase=*/IsBaseDtor: true, Pred, Dst, Options&: CallOpts);
1486}
1487
1488void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
1489 ExplodedNode *Pred, ExplodedNodeSet &Dst) {
1490 const auto *DtorDecl = D.getDestructorDecl(astContext&: getContext());
1491 const FieldDecl *Member = D.getFieldDecl();
1492 QualType T = Member->getType();
1493 ProgramStateRef State = Pred->getState();
1494 const StackFrame *SF = Pred->getStackFrame();
1495
1496 const auto *CurDtor = cast<CXXDestructorDecl>(Val: SF->getDecl());
1497 Loc ThisStorageLoc = getSValBuilder().getCXXThis(D: CurDtor, SF);
1498 Loc ThisLoc = State->getSVal(LV: ThisStorageLoc).castAs<Loc>();
1499 SVal FieldVal = State->getLValue(decl: Member, Base: ThisLoc);
1500
1501 unsigned Idx = 0;
1502 if (isa<ArrayType>(Val: T)) {
1503 SVal ElementCount;
1504 std::tie(args&: State, args&: Idx) = prepareStateForArrayDestruction(
1505 State, Region: FieldVal.getAsRegion(), ElementTy: T, SF, ElementCountVal: &ElementCount);
1506
1507 if (ElementCount.isConstant()) {
1508 uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
1509 assert(ArrayLength &&
1510 "A member dtor for a 0 length array shouldn't be triggered!");
1511
1512 // Still handle this case if we don't have assertions enabled.
1513 if (!ArrayLength) {
1514 static SimpleProgramPointTag PT(
1515 "ExprEngine", "Skipping member 0 length array destruction, which "
1516 "shouldn't be in the CFG.");
1517 PostImplicitCall PP(DtorDecl, Member->getLocation(), SF,
1518 getCFGElementRef(), &PT);
1519 Engine.makeNode(Loc: PP, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
1520 return;
1521 }
1522 }
1523 }
1524
1525 EvalCallOptions CallOpts;
1526 FieldVal =
1527 makeElementRegion(State, LValue: FieldVal, Ty&: T, IsArray&: CallOpts.IsArrayCtorOrDtor, Idx);
1528
1529 static SimpleProgramPointTag PT("ExprEngine",
1530 "Prepare for object destruction");
1531 PreImplicitCall PP(DtorDecl, Member->getLocation(), SF, getCFGElementRef(),
1532 &PT);
1533 Pred = Engine.makeNode(Loc: PP, State, Pred);
1534
1535 if (!Pred)
1536 return;
1537
1538 VisitCXXDestructor(ObjectType: T, Dest: FieldVal.getAsRegion(), S: CurDtor->getBody(),
1539 /*IsBase=*/IsBaseDtor: false, Pred, Dst, Options&: CallOpts);
1540}
1541
1542void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
1543 ExplodedNode *Pred,
1544 ExplodedNodeSet &Dst) {
1545 const CXXBindTemporaryExpr *BTE = D.getBindTemporaryExpr();
1546 ProgramStateRef State = Pred->getState();
1547 const StackFrame *SF = Pred->getStackFrame();
1548 const MemRegion *MR = nullptr;
1549
1550 if (std::optional<SVal> V = getObjectUnderConstruction(State, Item: BTE, SF)) {
1551 // FIXME: Currently we insert temporary destructors for default parameters,
1552 // but we don't insert the constructors, so the entry in
1553 // ObjectsUnderConstruction may be missing.
1554 State = finishObjectConstruction(State, Item: BTE, SF);
1555 MR = V->getAsRegion();
1556 }
1557
1558 // If copy elision has occurred, and the constructor corresponding to the
1559 // destructor was elided, we need to skip the destructor as well.
1560 if (isDestructorElided(State, BTE, SF)) {
1561 State = cleanupElidedDestructor(State, BTE, SF);
1562 PostImplicitCall PP(D.getDestructorDecl(astContext&: getContext()), BTE->getBeginLoc(),
1563 SF, getCFGElementRef());
1564 Dst.insert(N: Engine.makeNode(Loc: PP, State, Pred));
1565 return;
1566 }
1567
1568 ExplodedNode *CleanPred = Engine.makePostStmtNode(S: BTE, State, Pred);
1569 if (!CleanPred || CleanPred->isSink()) {
1570 // FIXME: We can get a null node here due to temporaries being
1571 // bound to default parameters.
1572 // Sink check is just PosteriorlyOverconstrained paranoia.
1573 CleanPred = Pred;
1574 }
1575
1576 QualType T = BTE->getSubExpr()->getType();
1577
1578 EvalCallOptions CallOpts;
1579 CallOpts.IsTemporaryCtorOrDtor = true;
1580 if (!MR) {
1581 // FIXME: If we have no MR, we still need to unwrap the array to avoid
1582 // destroying the whole array at once.
1583 //
1584 // For this case there is no universal solution as there is no way to
1585 // directly create an array of temporary objects. There are some expressions
1586 // however which can create temporary objects and have an array type.
1587 //
1588 // E.g.: std::initializer_list<S>{S(), S()};
1589 //
1590 // The expression above has a type of 'const struct S[2]' but it's a single
1591 // 'std::initializer_list<>'. The destructors of the 2 temporary 'S()'
1592 // objects will be called anyway, because they are 2 separate objects in 2
1593 // separate clusters, i.e.: not an array.
1594 //
1595 // Now the 'std::initializer_list<>' is not an array either even though it
1596 // has the type of an array. The point is, we only want to invoke the
1597 // destructor for the initializer list once not twice or so.
1598 while (const ArrayType *AT = getContext().getAsArrayType(T)) {
1599 T = AT->getElementType();
1600
1601 // FIXME: Enable this flag once we handle this case properly.
1602 // CallOpts.IsArrayCtorOrDtor = true;
1603 }
1604 } else {
1605 // FIXME: We'd eventually need to makeElementRegion() trick here,
1606 // but for now we don't have the respective construction contexts,
1607 // so MR would always be null in this case. Do nothing for now.
1608 }
1609 VisitCXXDestructor(ObjectType: T, Dest: MR, S: BTE,
1610 /*IsBase=*/IsBaseDtor: false, Pred: CleanPred, Dst, Options&: CallOpts);
1611}
1612
1613void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
1614 ExplodedNode *Pred,
1615 ExplodedNodeSet &Dst,
1616 const CFGBlock *DstT,
1617 const CFGBlock *DstF) {
1618 ProgramStateRef State = Pred->getState();
1619 const StackFrame *SF = Pred->getStackFrame();
1620
1621 std::optional<SVal> Obj = getObjectUnderConstruction(State, Item: BTE, SF);
1622 if (const CFGBlock *DstBlock = Obj ? DstT : DstF) {
1623 BlockEdge BE(getCurrBlock(), DstBlock, SF);
1624 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred));
1625 }
1626}
1627
1628void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
1629 ExplodedNodeSet &PreVisit,
1630 ExplodedNodeSet &Dst) {
1631 // This is a fallback solution in case we didn't have a construction
1632 // context when we were constructing the temporary. Otherwise the map should
1633 // have been populated there.
1634 if (!getAnalysisManager().options.ShouldIncludeTemporaryDtorsInCFG) {
1635 // In case we don't have temporary destructors in the CFG, do not mark
1636 // the initialization - we would otherwise never clean it up.
1637 Dst = PreVisit;
1638 return;
1639 }
1640 for (ExplodedNode *Node : PreVisit) {
1641 ProgramStateRef State = Node->getState();
1642 const StackFrame *SF = Node->getStackFrame();
1643 if (!getObjectUnderConstruction(State, Item: BTE, SF)) {
1644 // FIXME: Currently the state might also already contain the marker due to
1645 // incorrect handling of temporaries bound to default parameters; for
1646 // those, we currently skip the CXXBindTemporaryExpr but rely on adding
1647 // temporary destructor nodes.
1648 State = addObjectUnderConstruction(State, Item: BTE, SF, V: UnknownVal());
1649 }
1650 Dst.insert(N: Engine.makePostStmtNode(S: BTE, State, Pred: Node));
1651 }
1652}
1653
1654ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State,
1655 ArrayRef<SVal> Vs,
1656 PointerEscapeKind K,
1657 const CallEvent *Call) const {
1658 class CollectReachableSymbolsCallback final : public SymbolVisitor {
1659 InvalidatedSymbols &Symbols;
1660
1661 public:
1662 explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols)
1663 : Symbols(Symbols) {}
1664
1665 const InvalidatedSymbols &getSymbols() const { return Symbols; }
1666
1667 bool VisitSymbol(SymbolRef Sym) override {
1668 Symbols.insert(V: Sym);
1669 return true;
1670 }
1671 };
1672 InvalidatedSymbols Symbols;
1673 CollectReachableSymbolsCallback CallBack(Symbols);
1674 for (SVal V : Vs)
1675 State->scanReachableSymbols(val: V, visitor&: CallBack);
1676
1677 return getCheckerManager().runCheckersForPointerEscape(
1678 State, Escaped: CallBack.getSymbols(), Call, Kind: K, ITraits: nullptr);
1679}
1680
1681void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
1682 ExplodedNodeSet &Dst) {
1683 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1684 S->getBeginLoc(), "Error evaluating statement");
1685
1686 assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens());
1687
1688 switch (S->getStmtClass()) {
1689 // C++, OpenMP and ARC stuff we don't support yet.
1690 case Stmt::CXXDependentScopeMemberExprClass:
1691 case Stmt::CXXReflectExprClass:
1692 case Stmt::CXXTryStmtClass:
1693 case Stmt::CXXTypeidExprClass:
1694 case Stmt::CXXUuidofExprClass:
1695 case Stmt::CXXFoldExprClass:
1696 case Stmt::MSPropertyRefExprClass:
1697 case Stmt::MSPropertySubscriptExprClass:
1698 case Stmt::CXXUnresolvedConstructExprClass:
1699 case Stmt::DependentScopeDeclRefExprClass:
1700 case Stmt::ArrayTypeTraitExprClass:
1701 case Stmt::ExpressionTraitExprClass:
1702 case Stmt::UnresolvedLookupExprClass:
1703 case Stmt::UnresolvedMemberExprClass:
1704 case Stmt::RecoveryExprClass:
1705 case Stmt::CXXNoexceptExprClass:
1706 case Stmt::PackExpansionExprClass:
1707 case Stmt::PackIndexingExprClass:
1708 case Stmt::SubstNonTypeTemplateParmPackExprClass:
1709 case Stmt::FunctionParmPackExprClass:
1710 case Stmt::CoroutineBodyStmtClass:
1711 case Stmt::CoawaitExprClass:
1712 case Stmt::DependentCoawaitExprClass:
1713 case Stmt::CoreturnStmtClass:
1714 case Stmt::CoyieldExprClass:
1715 case Stmt::SEHTryStmtClass:
1716 case Stmt::SEHExceptStmtClass:
1717 case Stmt::SEHLeaveStmtClass:
1718 case Stmt::SEHFinallyStmtClass:
1719 case Stmt::CXXExpansionStmtPatternClass:
1720 case Stmt::CXXExpansionStmtInstantiationClass:
1721 case Stmt::CXXExpansionSelectExprClass:
1722 case Stmt::OMPCanonicalLoopClass:
1723 case Stmt::OMPParallelDirectiveClass:
1724 case Stmt::OMPSimdDirectiveClass:
1725 case Stmt::OMPForDirectiveClass:
1726 case Stmt::OMPForSimdDirectiveClass:
1727 case Stmt::OMPSectionsDirectiveClass:
1728 case Stmt::OMPSectionDirectiveClass:
1729 case Stmt::OMPScopeDirectiveClass:
1730 case Stmt::OMPSingleDirectiveClass:
1731 case Stmt::OMPMasterDirectiveClass:
1732 case Stmt::OMPCriticalDirectiveClass:
1733 case Stmt::OMPParallelForDirectiveClass:
1734 case Stmt::OMPParallelForSimdDirectiveClass:
1735 case Stmt::OMPParallelSectionsDirectiveClass:
1736 case Stmt::OMPParallelMasterDirectiveClass:
1737 case Stmt::OMPParallelMaskedDirectiveClass:
1738 case Stmt::OMPTaskDirectiveClass:
1739 case Stmt::OMPTaskyieldDirectiveClass:
1740 case Stmt::OMPBarrierDirectiveClass:
1741 case Stmt::OMPTaskwaitDirectiveClass:
1742 case Stmt::OMPErrorDirectiveClass:
1743 case Stmt::OMPTaskgroupDirectiveClass:
1744 case Stmt::OMPFlushDirectiveClass:
1745 case Stmt::OMPDepobjDirectiveClass:
1746 case Stmt::OMPScanDirectiveClass:
1747 case Stmt::OMPOrderedDirectiveClass:
1748 case Stmt::OMPAtomicDirectiveClass:
1749 case Stmt::OMPAssumeDirectiveClass:
1750 case Stmt::OMPTargetDirectiveClass:
1751 case Stmt::OMPTargetDataDirectiveClass:
1752 case Stmt::OMPTargetEnterDataDirectiveClass:
1753 case Stmt::OMPTargetExitDataDirectiveClass:
1754 case Stmt::OMPTargetParallelDirectiveClass:
1755 case Stmt::OMPTargetParallelForDirectiveClass:
1756 case Stmt::OMPTargetUpdateDirectiveClass:
1757 case Stmt::OMPTeamsDirectiveClass:
1758 case Stmt::OMPCancellationPointDirectiveClass:
1759 case Stmt::OMPCancelDirectiveClass:
1760 case Stmt::OMPTaskLoopDirectiveClass:
1761 case Stmt::OMPTaskLoopSimdDirectiveClass:
1762 case Stmt::OMPMasterTaskLoopDirectiveClass:
1763 case Stmt::OMPMaskedTaskLoopDirectiveClass:
1764 case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
1765 case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
1766 case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
1767 case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
1768 case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
1769 case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
1770 case Stmt::OMPDistributeDirectiveClass:
1771 case Stmt::OMPDistributeParallelForDirectiveClass:
1772 case Stmt::OMPDistributeParallelForSimdDirectiveClass:
1773 case Stmt::OMPDistributeSimdDirectiveClass:
1774 case Stmt::OMPTargetParallelForSimdDirectiveClass:
1775 case Stmt::OMPTargetSimdDirectiveClass:
1776 case Stmt::OMPTeamsDistributeDirectiveClass:
1777 case Stmt::OMPTeamsDistributeSimdDirectiveClass:
1778 case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
1779 case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
1780 case Stmt::OMPTargetTeamsDirectiveClass:
1781 case Stmt::OMPTargetTeamsDistributeDirectiveClass:
1782 case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
1783 case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
1784 case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
1785 case Stmt::OMPReverseDirectiveClass:
1786 case Stmt::OMPStripeDirectiveClass:
1787 case Stmt::OMPTileDirectiveClass:
1788 case Stmt::OMPInterchangeDirectiveClass:
1789 case Stmt::OMPSplitDirectiveClass:
1790 case Stmt::OMPFuseDirectiveClass:
1791 case Stmt::OMPInteropDirectiveClass:
1792 case Stmt::OMPDispatchDirectiveClass:
1793 case Stmt::OMPMaskedDirectiveClass:
1794 case Stmt::OMPGenericLoopDirectiveClass:
1795 case Stmt::OMPTeamsGenericLoopDirectiveClass:
1796 case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
1797 case Stmt::OMPParallelGenericLoopDirectiveClass:
1798 case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
1799 case Stmt::CapturedStmtClass:
1800 case Stmt::SYCLKernelCallStmtClass:
1801 case Stmt::UnresolvedSYCLKernelCallStmtClass:
1802 case Stmt::OpenACCComputeConstructClass:
1803 case Stmt::OpenACCLoopConstructClass:
1804 case Stmt::OpenACCCombinedConstructClass:
1805 case Stmt::OpenACCDataConstructClass:
1806 case Stmt::OpenACCEnterDataConstructClass:
1807 case Stmt::OpenACCExitDataConstructClass:
1808 case Stmt::OpenACCHostDataConstructClass:
1809 case Stmt::OpenACCWaitConstructClass:
1810 case Stmt::OpenACCCacheConstructClass:
1811 case Stmt::OpenACCInitConstructClass:
1812 case Stmt::OpenACCShutdownConstructClass:
1813 case Stmt::OpenACCSetConstructClass:
1814 case Stmt::OpenACCUpdateConstructClass:
1815 case Stmt::OpenACCAtomicConstructClass:
1816 case Stmt::OMPUnrollDirectiveClass:
1817 case Stmt::OMPMetaDirectiveClass:
1818 case Stmt::HLSLOutArgExprClass: {
1819 const ExplodedNode *Node = Engine.makePostStmtNode(
1820 S, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
1821 Engine.addAbortedBlock(node: Node, block: getCurrBlock());
1822 break;
1823 }
1824
1825 case Stmt::ParenExprClass:
1826 llvm_unreachable("ParenExprs already handled.");
1827 case Stmt::GenericSelectionExprClass:
1828 llvm_unreachable("GenericSelectionExprs already handled.");
1829 // Cases that should never be evaluated simply because they shouldn't
1830 // appear in the CFG.
1831 case Stmt::BreakStmtClass:
1832 case Stmt::CaseStmtClass:
1833 case Stmt::CompoundStmtClass:
1834 case Stmt::ContinueStmtClass:
1835 case Stmt::CXXForRangeStmtClass:
1836 case Stmt::DefaultStmtClass:
1837 case Stmt::DoStmtClass:
1838 case Stmt::ForStmtClass:
1839 case Stmt::GotoStmtClass:
1840 case Stmt::IfStmtClass:
1841 case Stmt::IndirectGotoStmtClass:
1842 case Stmt::LabelStmtClass:
1843 case Stmt::NoStmtClass:
1844 case Stmt::NullStmtClass:
1845 case Stmt::SwitchStmtClass:
1846 case Stmt::WhileStmtClass:
1847 case Stmt::DeferStmtClass:
1848 case Expr::MSDependentExistsStmtClass:
1849 llvm_unreachable("Stmt should not be in analyzer evaluation loop");
1850 case Stmt::ImplicitValueInitExprClass:
1851 // These nodes are shared in the CFG and would case caching out.
1852 // Moreover, no additional evaluation required for them, the
1853 // analyzer can reconstruct these values from the AST.
1854 llvm_unreachable("Should be pruned from CFG");
1855
1856 case Stmt::ObjCSubscriptRefExprClass:
1857 case Stmt::ObjCPropertyRefExprClass:
1858 llvm_unreachable("These are handled by PseudoObjectExpr");
1859
1860 case Stmt::GNUNullExprClass: {
1861 // GNU __null is a pointer-width integer, not an actual pointer.
1862 SVal Val = svalBuilder.makeIntValWithWidth(ptrType: getContext().VoidPtrTy, integer: 0);
1863 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: cast<Expr>(Val: S), V: Val));
1864 break;
1865 }
1866
1867 case Stmt::ObjCAtSynchronizedStmtClass:
1868 VisitObjCAtSynchronizedStmt(S: cast<ObjCAtSynchronizedStmt>(Val: S), Pred, Dst);
1869 break;
1870
1871 case Expr::ConstantExprClass:
1872 case Stmt::ExprWithCleanupsClass:
1873 Dst.insert(N: Pred);
1874 // Handled due to fully linearised CFG.
1875 break;
1876
1877 case Stmt::CXXBindTemporaryExprClass: {
1878 ExplodedNodeSet PreVisit;
1879 getCheckerManager().runCheckersForPreStmt(Dst&: PreVisit, Src: Pred, S, Eng&: *this);
1880 ExplodedNodeSet Next;
1881 VisitCXXBindTemporaryExpr(BTE: cast<CXXBindTemporaryExpr>(Val: S), PreVisit, Dst&: Next);
1882 getCheckerManager().runCheckersForPostStmt(Dst, Src: Next, S, Eng&: *this);
1883 break;
1884 }
1885
1886 case Stmt::ArrayInitLoopExprClass:
1887 VisitArrayInitLoopExpr(Ex: cast<ArrayInitLoopExpr>(Val: S), Pred, Dst);
1888 break;
1889 // Cases not handled yet; but will handle some day.
1890 case Stmt::DesignatedInitExprClass:
1891 case Stmt::DesignatedInitUpdateExprClass:
1892 case Stmt::ArrayInitIndexExprClass:
1893 case Stmt::ExtVectorElementExprClass:
1894 case Stmt::MatrixElementExprClass:
1895 case Stmt::ImaginaryLiteralClass:
1896 case Stmt::ObjCAtCatchStmtClass:
1897 case Stmt::ObjCAtFinallyStmtClass:
1898 case Stmt::ObjCAtTryStmtClass:
1899 case Stmt::ObjCAutoreleasePoolStmtClass:
1900 case Stmt::ObjCEncodeExprClass:
1901 case Stmt::ObjCIsaExprClass:
1902 case Stmt::ObjCProtocolExprClass:
1903 case Stmt::ObjCSelectorExprClass:
1904 case Stmt::ParenListExprClass:
1905 case Stmt::ShuffleVectorExprClass:
1906 case Stmt::ConvertVectorExprClass:
1907 case Stmt::VAArgExprClass:
1908 case Stmt::CUDAKernelCallExprClass:
1909 case Stmt::OpaqueValueExprClass:
1910 case Stmt::AsTypeExprClass:
1911 case Stmt::ConceptSpecializationExprClass:
1912 case Stmt::CXXRewrittenBinaryOperatorClass:
1913 case Stmt::RequiresExprClass:
1914 case Stmt::EmbedExprClass:
1915 // Fall through.
1916
1917 // Cases we intentionally don't evaluate, since they don't need
1918 // to be explicitly evaluated.
1919 case Stmt::PredefinedExprClass:
1920 case Stmt::AddrLabelExprClass:
1921 case Stmt::IntegerLiteralClass:
1922 case Stmt::FixedPointLiteralClass:
1923 case Stmt::CharacterLiteralClass:
1924 case Stmt::CXXScalarValueInitExprClass:
1925 case Stmt::CXXBoolLiteralExprClass:
1926 case Stmt::ObjCBoolLiteralExprClass:
1927 case Stmt::ObjCAvailabilityCheckExprClass:
1928 case Stmt::FloatingLiteralClass:
1929 case Stmt::NoInitExprClass:
1930 case Stmt::SizeOfPackExprClass:
1931 case Stmt::StringLiteralClass:
1932 case Stmt::SourceLocExprClass:
1933 case Stmt::ObjCStringLiteralClass:
1934 case Stmt::CXXPseudoDestructorExprClass:
1935 case Stmt::SubstNonTypeTemplateParmExprClass:
1936 case Stmt::CXXNullPtrLiteralExprClass:
1937 case Stmt::ArraySectionExprClass:
1938 case Stmt::OMPArrayShapingExprClass:
1939 case Stmt::OMPIteratorExprClass:
1940 case Stmt::SYCLUniqueStableNameExprClass:
1941 case Stmt::OpenACCAsteriskSizeExprClass:
1942 case Stmt::TypeTraitExprClass: {
1943 ExplodedNodeSet preVisit;
1944 getCheckerManager().runCheckersForPreStmt(Dst&: preVisit, Src: Pred, S, Eng&: *this);
1945 getCheckerManager().runCheckersForPostStmt(Dst, Src: preVisit, S, Eng&: *this);
1946 break;
1947 }
1948
1949 case Stmt::AttributedStmtClass: {
1950 VisitAttributedStmt(A: cast<AttributedStmt>(Val: S), Pred, Dst);
1951 break;
1952 }
1953
1954 case Stmt::CXXDefaultArgExprClass:
1955 case Stmt::CXXDefaultInitExprClass: {
1956 ExplodedNodeSet PreVisit;
1957 getCheckerManager().runCheckersForPreStmt(Dst&: PreVisit, Src: Pred, S, Eng&: *this);
1958
1959 ExplodedNodeSet Tmp;
1960
1961 const Expr *ArgE;
1962 if (const auto *DefE = dyn_cast<CXXDefaultArgExpr>(Val: S))
1963 ArgE = DefE->getExpr();
1964 else if (const auto *DefE = dyn_cast<CXXDefaultInitExpr>(Val: S))
1965 ArgE = DefE->getExpr();
1966 else
1967 llvm_unreachable("unknown constant wrapper kind");
1968
1969 bool IsTemporary = false;
1970 if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Val: ArgE)) {
1971 ArgE = MTE->getSubExpr();
1972 IsTemporary = true;
1973 }
1974
1975 std::optional<SVal> ConstantVal = svalBuilder.getConstantVal(E: ArgE);
1976 if (!ConstantVal)
1977 ConstantVal = UnknownVal();
1978
1979 const StackFrame *SF = Pred->getStackFrame();
1980 for (const auto I : PreVisit) {
1981 ProgramStateRef State = I->getState();
1982 State = State->BindExpr(E: cast<Expr>(Val: S), SF, V: *ConstantVal);
1983 if (IsTemporary)
1984 State = createTemporaryRegionIfNeeded(State, SF, InitWithAdjustments: cast<Expr>(Val: S),
1985 Result: cast<Expr>(Val: S));
1986 Tmp.insert(N: Engine.makePostStmtNode(S, State, Pred: I));
1987 }
1988
1989 getCheckerManager().runCheckersForPostStmt(Dst, Src: Tmp, S, Eng&: *this);
1990 break;
1991 }
1992
1993 // Cases we evaluate as opaque expressions, conjuring a symbol.
1994 case Stmt::CXXStdInitializerListExprClass:
1995 case Expr::ObjCArrayLiteralClass:
1996 case Expr::ObjCDictionaryLiteralClass:
1997 case Expr::ObjCBoxedExprClass: {
1998 ExplodedNodeSet preVisit;
1999 getCheckerManager().runCheckersForPreStmt(Dst&: preVisit, Src: Pred, S, Eng&: *this);
2000
2001 ExplodedNodeSet Tmp;
2002
2003 const auto *Ex = cast<Expr>(Val: S);
2004 QualType resultType = Ex->getType();
2005
2006 for (const auto N : preVisit) {
2007 const StackFrame *SF = N->getStackFrame();
2008 SVal result = svalBuilder.conjureSymbolVal(
2009 /*symbolTag=*/nullptr, elem: getCFGElementRef(), SF, type: resultType,
2010 count: getNumVisitedCurrent());
2011 ProgramStateRef State = N->getState()->BindExpr(E: Ex, SF, V: result);
2012
2013 // Escape pointers passed into the list, unless it's an ObjC boxed
2014 // expression which is not a boxable C structure.
2015 if (!(isa<ObjCBoxedExpr>(Val: Ex) &&
2016 !cast<ObjCBoxedExpr>(Val: Ex)->getSubExpr()
2017 ->getType()->isRecordType()))
2018 for (auto Child : Ex->children()) {
2019 assert(Child);
2020 const auto *ChildExpr = dyn_cast<Expr>(Val: Child);
2021 SVal Val = ChildExpr ? State->getSVal(E: ChildExpr, SF) : UnknownVal();
2022 State = escapeValues(State, Vs: Val, K: PSK_EscapeOther);
2023 }
2024
2025 Tmp.insert(N: Engine.makePostStmtNode(S, State, Pred: N));
2026 }
2027
2028 getCheckerManager().runCheckersForPostStmt(Dst, Src: Tmp, S, Eng&: *this);
2029 break;
2030 }
2031
2032 case Stmt::ArraySubscriptExprClass:
2033 VisitArraySubscriptExpr(Ex: cast<ArraySubscriptExpr>(Val: S), Pred, Dst);
2034 break;
2035
2036 case Stmt::MatrixSingleSubscriptExprClass:
2037 llvm_unreachable(
2038 "Support for MatrixSingleSubscriptExprClass is not implemented.");
2039 break;
2040
2041 case Stmt::MatrixSubscriptExprClass:
2042 llvm_unreachable("Support for MatrixSubscriptExpr is not implemented.");
2043 break;
2044
2045 case Stmt::GCCAsmStmtClass: {
2046 ExplodedNodeSet PreVisit;
2047 getCheckerManager().runCheckersForPreStmt(Dst&: PreVisit, Src: Pred, S, Eng&: *this);
2048 ExplodedNodeSet PostVisit;
2049 for (ExplodedNode *const N : PreVisit)
2050 VisitGCCAsmStmt(A: cast<GCCAsmStmt>(Val: S), Pred: N, Dst&: PostVisit);
2051 getCheckerManager().runCheckersForPostStmt(Dst, Src: PostVisit, S, Eng&: *this);
2052 break;
2053 }
2054
2055 case Stmt::MSAsmStmtClass:
2056 VisitMSAsmStmt(A: cast<MSAsmStmt>(Val: S), Pred, Dst);
2057 break;
2058
2059 case Stmt::BlockExprClass:
2060 VisitBlockExpr(BE: cast<BlockExpr>(Val: S), Pred, Dst);
2061 break;
2062
2063 case Stmt::LambdaExprClass:
2064 if (AMgr.options.ShouldInlineLambdas) {
2065 VisitLambdaExpr(LE: cast<LambdaExpr>(Val: S), Pred, Dst);
2066 } else {
2067 const ExplodedNode *Node = Engine.makePostStmtNode(
2068 S, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
2069 Engine.addAbortedBlock(node: Node, block: getCurrBlock());
2070 }
2071 break;
2072
2073 case Stmt::BinaryOperatorClass: {
2074 const auto *B = cast<BinaryOperator>(Val: S);
2075 if (B->isLogicalOp()) {
2076 VisitLogicalExpr(B, Pred, Dst);
2077 break;
2078 } else if (B->getOpcode() == BO_Comma) {
2079 SVal Val =
2080 Pred->getState()->getSVal(E: B->getRHS(), SF: Pred->getStackFrame());
2081 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: B, V: Val));
2082 break;
2083 }
2084
2085 if (AMgr.options.ShouldEagerlyAssume &&
2086 (B->isRelationalOp() || B->isEqualityOp())) {
2087 ExplodedNodeSet Tmp;
2088 VisitBinaryOperator(B: cast<BinaryOperator>(Val: S), Pred, Dst&: Tmp);
2089 evalEagerlyAssumeBifurcation(Dst, Src&: Tmp, Ex: cast<Expr>(Val: S));
2090 }
2091 else
2092 VisitBinaryOperator(B: cast<BinaryOperator>(Val: S), Pred, Dst);
2093
2094 break;
2095 }
2096
2097 case Stmt::CXXOperatorCallExprClass:
2098 case Stmt::CallExprClass:
2099 case Stmt::CXXMemberCallExprClass:
2100 case Stmt::UserDefinedLiteralClass:
2101 VisitCallExpr(CE: cast<CallExpr>(Val: S), Pred, Dst);
2102 break;
2103
2104 case Stmt::CXXCatchStmtClass:
2105 VisitCXXCatchStmt(CS: cast<CXXCatchStmt>(Val: S), Pred, Dst);
2106 break;
2107
2108 case Stmt::CXXTemporaryObjectExprClass:
2109 case Stmt::CXXConstructExprClass:
2110 VisitCXXConstructExpr(E: cast<CXXConstructExpr>(Val: S), Pred, Dst);
2111 break;
2112
2113 case Stmt::CXXInheritedCtorInitExprClass:
2114 VisitCXXInheritedCtorInitExpr(E: cast<CXXInheritedCtorInitExpr>(Val: S), Pred,
2115 Dst);
2116 break;
2117
2118 case Stmt::CXXNewExprClass: {
2119
2120 ExplodedNodeSet PreVisit;
2121 getCheckerManager().runCheckersForPreStmt(Dst&: PreVisit, Src: Pred, S, Eng&: *this);
2122
2123 ExplodedNodeSet PostVisit;
2124 for (const auto i : PreVisit)
2125 VisitCXXNewExpr(CNE: cast<CXXNewExpr>(Val: S), Pred: i, Dst&: PostVisit);
2126
2127 getCheckerManager().runCheckersForPostStmt(Dst, Src: PostVisit, S, Eng&: *this);
2128 break;
2129 }
2130
2131 case Stmt::CXXDeleteExprClass: {
2132 ExplodedNodeSet PreVisit;
2133 const auto *CDE = cast<CXXDeleteExpr>(Val: S);
2134 getCheckerManager().runCheckersForPreStmt(Dst&: PreVisit, Src: Pred, S, Eng&: *this);
2135 ExplodedNodeSet PostVisit;
2136 getCheckerManager().runCheckersForPostStmt(Dst&: PostVisit, Src: PreVisit, S, Eng&: *this);
2137
2138 for (const auto i : PostVisit)
2139 VisitCXXDeleteExpr(CDE, Pred: i, Dst);
2140
2141 break;
2142 }
2143 // FIXME: ChooseExpr is really a constant. We need to fix
2144 // the CFG do not model them as explicit control-flow.
2145
2146 case Stmt::ChooseExprClass: { // __builtin_choose_expr
2147 const auto *C = cast<ChooseExpr>(Val: S);
2148 VisitGuardedExpr(Ex: C, L: C->getLHS(), R: C->getRHS(), Pred, Dst);
2149 break;
2150 }
2151
2152 case Stmt::CompoundAssignOperatorClass:
2153 VisitBinaryOperator(B: cast<BinaryOperator>(Val: S), Pred, Dst);
2154 break;
2155
2156 case Stmt::CompoundLiteralExprClass:
2157 VisitCompoundLiteralExpr(CL: cast<CompoundLiteralExpr>(Val: S), Pred, Dst);
2158 break;
2159
2160 case Stmt::BinaryConditionalOperatorClass:
2161 case Stmt::ConditionalOperatorClass: { // '?' operator
2162 const auto *C = cast<AbstractConditionalOperator>(Val: S);
2163 VisitGuardedExpr(Ex: C, L: C->getTrueExpr(), R: C->getFalseExpr(), Pred, Dst);
2164 break;
2165 }
2166
2167 case Stmt::CXXThisExprClass:
2168 VisitCXXThisExpr(TE: cast<CXXThisExpr>(Val: S), Pred, Dst);
2169 break;
2170
2171 case Stmt::DeclRefExprClass: {
2172 const auto *DE = cast<DeclRefExpr>(Val: S);
2173 VisitCommonDeclRefExpr(DR: DE, D: DE->getDecl(), Pred, Dst);
2174 break;
2175 }
2176
2177 case Stmt::DeclStmtClass:
2178 VisitDeclStmt(DS: cast<DeclStmt>(Val: S), Pred, Dst);
2179 break;
2180
2181 case Stmt::ImplicitCastExprClass:
2182 case Stmt::CStyleCastExprClass:
2183 case Stmt::CXXStaticCastExprClass:
2184 case Stmt::CXXDynamicCastExprClass:
2185 case Stmt::CXXReinterpretCastExprClass:
2186 case Stmt::CXXConstCastExprClass:
2187 case Stmt::CXXFunctionalCastExprClass:
2188 case Stmt::BuiltinBitCastExprClass:
2189 case Stmt::ObjCBridgedCastExprClass:
2190 case Stmt::CXXAddrspaceCastExprClass: {
2191 const auto *C = cast<CastExpr>(Val: S);
2192 ExplodedNodeSet dstExpr;
2193 VisitCast(CastE: C, Ex: C->getSubExpr(), Pred, Dst&: dstExpr);
2194
2195 // Handle the postvisit checks.
2196 getCheckerManager().runCheckersForPostStmt(Dst, Src: dstExpr, S: C, Eng&: *this);
2197 break;
2198 }
2199
2200 case Expr::MaterializeTemporaryExprClass: {
2201 const auto *MTE = cast<MaterializeTemporaryExpr>(Val: S);
2202 ExplodedNodeSet dstPrevisit;
2203 getCheckerManager().runCheckersForPreStmt(Dst&: dstPrevisit, Src: Pred, S: MTE, Eng&: *this);
2204 ExplodedNodeSet dstExpr;
2205 for (const auto i : dstPrevisit)
2206 CreateCXXTemporaryObject(ME: MTE, Pred: i, Dst&: dstExpr);
2207 getCheckerManager().runCheckersForPostStmt(Dst, Src: dstExpr, S: MTE, Eng&: *this);
2208 break;
2209 }
2210
2211 case Stmt::InitListExprClass: {
2212 const InitListExpr *E = cast<InitListExpr>(Val: S);
2213 ConstructInitList(Source: E, Args: E->inits(), IsTransparent: E->isTransparent(), Pred, Dst);
2214 break;
2215 }
2216
2217 case Expr::CXXParenListInitExprClass: {
2218 const CXXParenListInitExpr *E = cast<CXXParenListInitExpr>(Val: S);
2219 ConstructInitList(Source: E, Args: E->getInitExprs(), /*IsTransparent*/ false, Pred,
2220 Dst);
2221 break;
2222 }
2223
2224 case Stmt::MemberExprClass:
2225 VisitMemberExpr(M: cast<MemberExpr>(Val: S), Pred, Dst);
2226 break;
2227
2228 case Stmt::AtomicExprClass:
2229 VisitAtomicExpr(E: cast<AtomicExpr>(Val: S), Pred, Dst);
2230 break;
2231
2232 case Stmt::ObjCIvarRefExprClass:
2233 VisitLvalObjCIvarRefExpr(DR: cast<ObjCIvarRefExpr>(Val: S), Pred, Dst);
2234 break;
2235
2236 case Stmt::ObjCForCollectionStmtClass:
2237 VisitObjCForCollectionStmt(S: cast<ObjCForCollectionStmt>(Val: S), Pred, Dst);
2238 break;
2239
2240 case Stmt::ObjCMessageExprClass:
2241 VisitObjCMessage(ME: cast<ObjCMessageExpr>(Val: S), Pred, Dst);
2242 break;
2243
2244 case Stmt::ObjCAtThrowStmtClass:
2245 case Stmt::CXXThrowExprClass:
2246 // FIXME: This is not complete. We basically treat @throw as
2247 // an abort.
2248 Engine.makePostStmtNode(S, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
2249 break;
2250
2251 case Stmt::ReturnStmtClass:
2252 VisitReturnStmt(R: cast<ReturnStmt>(Val: S), Pred, Dst);
2253 break;
2254
2255 case Stmt::OffsetOfExprClass: {
2256 ExplodedNodeSet PreVisit;
2257 getCheckerManager().runCheckersForPreStmt(Dst&: PreVisit, Src: Pred, S, Eng&: *this);
2258
2259 ExplodedNodeSet PostVisit;
2260 for (const auto Node : PreVisit)
2261 VisitOffsetOfExpr(Ex: cast<OffsetOfExpr>(Val: S), Pred: Node, Dst&: PostVisit);
2262
2263 getCheckerManager().runCheckersForPostStmt(Dst, Src: PostVisit, S, Eng&: *this);
2264 break;
2265 }
2266
2267 case Stmt::UnaryExprOrTypeTraitExprClass:
2268 VisitUnaryExprOrTypeTraitExpr(Ex: cast<UnaryExprOrTypeTraitExpr>(Val: S), Pred,
2269 Dst);
2270 break;
2271
2272 case Stmt::StmtExprClass: {
2273 const auto *SE = cast<StmtExpr>(Val: S);
2274
2275 if (SE->getSubStmt()->body_empty()) {
2276 // Empty statement expression.
2277 assert(SE->getType() == getContext().VoidTy
2278 && "Empty statement expression must have void type.");
2279 } else if (const auto *LastExpr =
2280 dyn_cast<Expr>(Val: *SE->getSubStmt()->body_rbegin())) {
2281 SVal Val = Pred->getState()->getSVal(E: LastExpr, SF: Pred->getStackFrame());
2282 Pred = Engine.makeNodeWithBinding(Pred, E: SE, V: Val);
2283 }
2284 Dst.insert(N: Pred);
2285 break;
2286 }
2287
2288 case Stmt::UnaryOperatorClass: {
2289 const auto *U = cast<UnaryOperator>(Val: S);
2290 if (AMgr.options.ShouldEagerlyAssume && (U->getOpcode() == UO_LNot)) {
2291 ExplodedNodeSet Tmp;
2292 VisitUnaryOperator(B: U, Pred, Dst&: Tmp);
2293 evalEagerlyAssumeBifurcation(Dst, Src&: Tmp, Ex: U);
2294 }
2295 else
2296 VisitUnaryOperator(B: U, Pred, Dst);
2297 break;
2298 }
2299
2300 case Stmt::PseudoObjectExprClass: {
2301 const auto *PE = cast<PseudoObjectExpr>(Val: S);
2302 SVal V = UnknownVal();
2303 if (const Expr *Result = PE->getResultExpr())
2304 V = Pred->getState()->getSVal(E: Result, SF: Pred->getStackFrame());
2305 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: PE, V));
2306 break;
2307 }
2308
2309 case Expr::ObjCIndirectCopyRestoreExprClass: {
2310 // ObjCIndirectCopyRestoreExpr implies passing a temporary for
2311 // correctness of lifetime management. Due to limited analysis
2312 // of ARC, this is implemented as direct arg passing.
2313 const auto *OIE = cast<ObjCIndirectCopyRestoreExpr>(Val: S);
2314 const Expr *E = OIE->getSubExpr();
2315 SVal V = Pred->getState()->getSVal(E, SF: Pred->getStackFrame());
2316 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: OIE, V));
2317 break;
2318 }
2319 }
2320}
2321
2322bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
2323 const StackFrame *CalleeSF) {
2324 const StackFrame *CallerSF = CalleeSF->getParent();
2325 assert(CalleeSF && CallerSF);
2326 ExplodedNode *BeforeProcessingCall = nullptr;
2327 const Expr *CE = CalleeSF->getCallSite();
2328
2329 // Find the first node before we started processing the call expression.
2330 while (N) {
2331 ProgramPoint L = N->getLocation();
2332 BeforeProcessingCall = N;
2333 N = N->pred_empty() ? nullptr : *(N->pred_begin());
2334
2335 // Skip the nodes corresponding to the inlined code.
2336 if (L.getStackFrame() != CallerSF)
2337 continue;
2338 // We reached the caller. Find the node right before we started
2339 // processing the call.
2340 if (L.isPurgeKind())
2341 continue;
2342 if (L.getAs<PreImplicitCall>())
2343 continue;
2344 if (L.getAs<CallEnter>())
2345 continue;
2346 if (std::optional<StmtPoint> SP = L.getAs<StmtPoint>())
2347 if (SP->getStmt() == CE)
2348 continue;
2349 break;
2350 }
2351
2352 if (!BeforeProcessingCall)
2353 return false;
2354
2355 // TODO: Clean up the unneeded nodes.
2356
2357 // Build an Epsilon node from which we will restart the analyzes.
2358 // Note that CE is permitted to be NULL!
2359 static SimpleProgramPointTag PT("ExprEngine", "Replay without inlining");
2360 ProgramPoint NewNodeLoc =
2361 EpsilonPoint(BeforeProcessingCall->getStackFrame(), CE, nullptr, &PT);
2362 // Add the special flag to GDM to signal retrying with no inlining.
2363 // Note, changing the state ensures that we are not going to cache out.
2364 // NOTE: This stores the call site (CE) in the state trait, but the the
2365 // actual pointer value is only checked by an assertion; for the analysis,
2366 // only the presence or absence of this trait matters.
2367 // TODO: If we are handling a destructor call, CE is nullpointer (because it
2368 // ultimately comes from the `Origin` of a `CXXDestructorCall`), which is
2369 // indistinguishable from the absence (default state) of this state trait.
2370 // I don't think that this bad logic causes actually observable problems, but
2371 // it would be nice to clean it up if somebody has time to do so.
2372 ProgramStateRef NewNodeState = BeforeProcessingCall->getState();
2373 NewNodeState = NewNodeState->set<ReplayWithoutInlining>(CE);
2374
2375 // Make the new node a successor of BeforeProcessingCall.
2376 bool IsNew = false;
2377 ExplodedNode *NewNode = G.getNode(L: NewNodeLoc, State: NewNodeState, IsSink: false, IsNew: &IsNew);
2378 // We cached out at this point. Caching out is common due to us backtracking
2379 // from the inlined function, which might spawn several paths.
2380 if (!IsNew)
2381 return true;
2382
2383 NewNode->addPredecessor(V: BeforeProcessingCall, G);
2384
2385 // Add the new node to the work list.
2386 Engine.enqueueStmtNode(N: NewNode, Block: CalleeSF->getCallSiteBlock(),
2387 Idx: CalleeSF->getIndex());
2388 NumTimesRetriedWithoutInlining++;
2389 return true;
2390}
2391
2392/// Block entrance. (Update counters).
2393/// FIXME: `BlockEdge &L` is only used for debug statistics, consider removing
2394/// it and using `BlockEntrance &BE` (where `BlockEntrance` is a subtype of
2395/// `ProgramPoint`) for statistical purposes.
2396void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
2397 const BlockEntrance &BE,
2398 NodeBuilder &Builder,
2399 ExplodedNode *Pred) {
2400 // If we reach a loop which has a known bound (and meets
2401 // other constraints) then consider completely unrolling it.
2402 if(AMgr.options.ShouldUnrollLoops) {
2403 unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
2404 const Stmt *Term = getCurrBlock()->getTerminatorStmt();
2405 if (Term) {
2406 ProgramStateRef NewState = updateLoopStack(LoopStmt: Term, ASTCtx&: AMgr.getASTContext(),
2407 Pred, maxVisitOnPath: maxBlockVisitOnPath);
2408 if (NewState != Pred->getState()) {
2409 ExplodedNode *UpdatedNode = Builder.generateNode(PP: BE, State: NewState, Pred);
2410 if (!UpdatedNode)
2411 return;
2412 Pred = UpdatedNode;
2413 }
2414 }
2415 // Is we are inside an unrolled loop then no need the check the counters.
2416 if(isUnrolledState(State: Pred->getState()))
2417 return;
2418 }
2419
2420 // If this block is terminated by a loop and it has already been visited the
2421 // maximum number of times, widen the loop.
2422 unsigned int BlockCount = getNumVisitedCurrent();
2423 if (BlockCount == AMgr.options.maxBlockVisitOnPath - 1 &&
2424 AMgr.options.ShouldWidenLoops) {
2425 const Stmt *Term = getCurrBlock()->getTerminatorStmt();
2426 if (!isa_and_nonnull<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(Val: Term))
2427 return;
2428
2429 // Widen.
2430 const StackFrame *SF = Pred->getStackFrame();
2431
2432 // FIXME:
2433 // We cannot use the CFG element from the via `ExprEngine::getCFGElementRef`
2434 // since we are currently at the block entrance and the current reference
2435 // would be stale. Ideally, we should pass on the terminator of the CFG
2436 // block, but the terminator cannot be referred as a CFG element.
2437 // Here we just pass the the first CFG element in the block.
2438 ProgramStateRef WidenedState = getWidenedLoopState(
2439 PrevState: Pred->getState(), SF, BlockCount, Elem: *getCurrBlock()->ref_begin());
2440 Builder.generateNode(PP: BE, State: WidenedState, Pred);
2441 return;
2442 }
2443
2444 // FIXME: Refactor this into a checker.
2445 if (BlockCount >= AMgr.options.maxBlockVisitOnPath) {
2446 static SimpleProgramPointTag Tag(TagProviderName, "Block count exceeded");
2447 const ProgramPoint TaggedLoc = BE.withTag(tag: &Tag);
2448 const ExplodedNode *Sink =
2449 Builder.generateSink(PP: TaggedLoc, State: Pred->getState(), Pred);
2450
2451 const StackFrame *SF = Pred->getStackFrame();
2452 if (!SF->inTopFrame()) {
2453 // FIXME: This will unconditionally prevent inlining this function (even
2454 // from other entry points), which is not a reasonable heuristic: even if
2455 // we reached max block count on this particular execution path, there
2456 // may be other execution paths (especially with other parametrizations)
2457 // where the analyzer can reach the end of the function (so there is no
2458 // natural reason to avoid inlining it). However, disabling this would
2459 // significantly increase the analysis time (because more entry points
2460 // would exhaust their allocated budget), so it must be compensated by a
2461 // different (more reasonable) reduction of analysis scope.
2462 Engine.FunctionSummaries->markShouldNotInline(D: SF->getDecl());
2463
2464 // Re-run the call evaluation without inlining it, by storing the
2465 // no-inlining policy in the state and enqueuing the new work item on
2466 // the list. Replay should almost never fail. Use the stats to catch it
2467 // if it does.
2468 if ((!AMgr.options.NoRetryExhausted && replayWithoutInlining(N: Pred, CalleeSF: SF)))
2469 return;
2470 NumMaxBlockCountReachedInInlined++;
2471 } else
2472 NumMaxBlockCountReached++;
2473
2474 // Make sink nodes as exhausted(for stats) only if retry failed.
2475 Engine.blocksExhausted.push_back(x: std::make_pair(x: L, y&: Sink));
2476 }
2477}
2478
2479void ExprEngine::runCheckersForBlockEntrance(const BlockEntrance &Entrance,
2480 ExplodedNode *Pred,
2481 ExplodedNodeSet &Dst) {
2482 llvm::PrettyStackTraceFormat CrashInfo(
2483 "Processing block entrance B%d -> B%d",
2484 Entrance.getPreviousBlock()->getBlockID(),
2485 Entrance.getBlock()->getBlockID());
2486 getCheckerManager().runCheckersForBlockEntrance(Dst, Src: Pred, Entrance, Eng&: *this);
2487}
2488
2489//===----------------------------------------------------------------------===//
2490// Branch processing.
2491//===----------------------------------------------------------------------===//
2492
2493/// RecoverCastedSymbol - A helper function for ProcessBranch that is used
2494/// to try to recover some path-sensitivity for casts of symbolic
2495/// integers that promote their values (which are currently not tracked well).
2496/// This function returns the SVal bound to Condition->IgnoreCasts if all the
2497// cast(s) did was sign-extend the original value.
2498static SVal RecoverCastedSymbol(ProgramStateRef state, const Stmt *Condition,
2499 const StackFrame *SF, ASTContext &Ctx) {
2500
2501 const auto *Ex = dyn_cast<Expr>(Val: Condition);
2502 if (!Ex)
2503 return UnknownVal();
2504
2505 uint64_t bits = 0;
2506 bool bitsInit = false;
2507
2508 while (const auto *CE = dyn_cast<CastExpr>(Val: Ex)) {
2509 QualType T = CE->getType();
2510
2511 if (!T->isIntegralOrEnumerationType())
2512 return UnknownVal();
2513
2514 uint64_t newBits = Ctx.getTypeSize(T);
2515 if (!bitsInit || newBits < bits) {
2516 bitsInit = true;
2517 bits = newBits;
2518 }
2519
2520 Ex = CE->getSubExpr();
2521 }
2522
2523 // We reached a non-cast. Is it a symbolic value?
2524 QualType T = Ex->getType();
2525
2526 if (!bitsInit || !T->isIntegralOrEnumerationType() ||
2527 Ctx.getTypeSize(T) > bits)
2528 return UnknownVal();
2529
2530 return state->getSVal(E: Ex, SF);
2531}
2532
2533#ifndef NDEBUG
2534static const Stmt *getRightmostLeaf(const Stmt *Condition) {
2535 while (Condition) {
2536 const auto *BO = dyn_cast<BinaryOperator>(Condition);
2537 if (!BO || !BO->isLogicalOp()) {
2538 return Condition;
2539 }
2540 Condition = BO->getRHS()->IgnoreParens();
2541 }
2542 return nullptr;
2543}
2544#endif
2545
2546// Returns the condition the branch at the end of 'B' depends on and whose value
2547// has been evaluated within 'B'.
2548// In most cases, the terminator condition of 'B' will be evaluated fully in
2549// the last statement of 'B'; in those cases, the resolved condition is the
2550// given 'Condition'.
2551// If the condition of the branch is a logical binary operator tree, the CFG is
2552// optimized: in that case, we know that the expression formed by all but the
2553// rightmost leaf of the logical binary operator tree must be true, and thus
2554// the branch condition is at this point equivalent to the truth value of that
2555// rightmost leaf; the CFG block thus only evaluates this rightmost leaf
2556// expression in its final statement. As the full condition in that case was
2557// not evaluated, and is thus not in the SVal cache, we need to use that leaf
2558// expression to evaluate the truth value of the condition in the current state
2559// space.
2560static const Stmt *ResolveCondition(const Stmt *Condition,
2561 const CFGBlock *B) {
2562 if (const auto *Ex = dyn_cast<Expr>(Val: Condition))
2563 Condition = Ex->IgnoreParens();
2564
2565 const auto *BO = dyn_cast<BinaryOperator>(Val: Condition);
2566 if (!BO || !BO->isLogicalOp())
2567 return Condition;
2568
2569 assert(B->getTerminator().isStmtBranch() &&
2570 "Other kinds of branches are handled separately!");
2571
2572 // For logical operations, we still have the case where some branches
2573 // use the traditional "merge" approach and others sink the branch
2574 // directly into the basic blocks representing the logical operation.
2575 // We need to distinguish between those two cases here.
2576
2577 // The invariants are still shifting, but it is possible that the
2578 // last element in a CFGBlock is not a CFGStmt. Look for the last
2579 // CFGStmt as the value of the condition.
2580 for (CFGElement Elem : llvm::reverse(C: *B)) {
2581 std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
2582 if (!CS)
2583 continue;
2584 const Stmt *LastStmt = CS->getStmt();
2585 assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition));
2586 return LastStmt;
2587 }
2588 llvm_unreachable("could not resolve condition");
2589}
2590
2591using ObjCForLctxPair =
2592 std::pair<const ObjCForCollectionStmt *, const StackFrame *>;
2593
2594REGISTER_MAP_WITH_PROGRAMSTATE(ObjCForHasMoreIterations, ObjCForLctxPair, bool)
2595
2596ProgramStateRef ExprEngine::setWhetherHasMoreIteration(
2597 ProgramStateRef State, const ObjCForCollectionStmt *O, const StackFrame *SF,
2598 bool HasMoreIteraton) {
2599 assert(!State->contains<ObjCForHasMoreIterations>({O, SF}));
2600 return State->set<ObjCForHasMoreIterations>(K: {O, SF}, E: HasMoreIteraton);
2601}
2602
2603ProgramStateRef ExprEngine::removeIterationState(ProgramStateRef State,
2604 const ObjCForCollectionStmt *O,
2605 const StackFrame *SF) {
2606 assert(State->contains<ObjCForHasMoreIterations>({O, SF}));
2607 return State->remove<ObjCForHasMoreIterations>(K: {O, SF});
2608}
2609
2610bool ExprEngine::hasMoreIteration(ProgramStateRef State,
2611 const ObjCForCollectionStmt *O,
2612 const StackFrame *SF) {
2613 assert(State->contains<ObjCForHasMoreIterations>({O, SF}));
2614 return *State->get<ObjCForHasMoreIterations>(key: {O, SF});
2615}
2616
2617/// Split the state on whether there are any more iterations left for this loop.
2618/// Returns a (HasMoreIteration, HasNoMoreIteration) pair, or std::nullopt when
2619/// the acquisition of the loop condition value failed.
2620static std::optional<std::pair<ProgramStateRef, ProgramStateRef>>
2621assumeCondition(const Stmt *ConditionStmt, ExplodedNode *N) {
2622 ProgramStateRef State = N->getState();
2623 if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(Val: ConditionStmt)) {
2624 bool HasMoreIteraton =
2625 ExprEngine::hasMoreIteration(State, O: ObjCFor, SF: N->getStackFrame());
2626 // Checkers have already ran on branch conditions, so the current
2627 // information as to whether the loop has more iteration becomes outdated
2628 // after this point.
2629 State =
2630 ExprEngine::removeIterationState(State, O: ObjCFor, SF: N->getStackFrame());
2631 if (HasMoreIteraton)
2632 return std::pair<ProgramStateRef, ProgramStateRef>{State, nullptr};
2633 else
2634 return std::pair<ProgramStateRef, ProgramStateRef>{nullptr, State};
2635 }
2636
2637 const auto *ConditionExpr = dyn_cast<Expr>(Val: ConditionStmt);
2638 assert(ConditionExpr && "The condition must be an Expr from here!");
2639
2640 SVal X = State->getSVal(E: ConditionExpr, SF: N->getStackFrame());
2641
2642 if (X.isUnknownOrUndef()) {
2643 // Give it a chance to recover from unknown.
2644 if (const auto *Ex = dyn_cast<Expr>(Val: ConditionExpr)) {
2645 if (Ex->getType()->isIntegralOrEnumerationType()) {
2646 // Try to recover some path-sensitivity. Right now casts of symbolic
2647 // integers that promote their values are currently not tracked well.
2648 // If 'ConditionExpr' is such an expression, try and recover the
2649 // underlying value and use that instead.
2650 SVal recovered =
2651 RecoverCastedSymbol(state: State, Condition: ConditionExpr, SF: N->getStackFrame(),
2652 Ctx&: N->getState()->getStateManager().getContext());
2653
2654 if (!recovered.isUnknown()) {
2655 X = recovered;
2656 }
2657 }
2658 }
2659 }
2660
2661 // If the condition is still unknown, give up.
2662 if (X.isUnknownOrUndef())
2663 return std::nullopt;
2664
2665 DefinedSVal V = X.castAs<DefinedSVal>();
2666
2667 ProgramStateRef StTrue, StFalse;
2668 return State->assume(Cond: V);
2669}
2670
2671void ExprEngine::processBranch(
2672 const Stmt *Condition, ExplodedNode *Pred, ExplodedNodeSet &Dst,
2673 const CFGBlock *DstT, const CFGBlock *DstF,
2674 std::optional<unsigned> IterationsCompletedInLoop) {
2675 assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) &&
2676 "CXXBindTemporaryExprs are handled by processBindTemporary.");
2677
2678 const StackFrame *SF = Pred->getStackFrame();
2679
2680 // Check for NULL conditions; e.g. "for(;;)"
2681 if (!Condition) {
2682 if (!DstT) {
2683 // I _hope_ that this "null condition + null transition to loop body"
2684 // case is impossible, but I cannot prove this, so let's cover it.
2685 return;
2686 }
2687 BlockEdge BE(getCurrBlock(), DstT, SF);
2688 Dst.insert(N: Engine.makeNode(Loc: BE, State: Pred->getState(), Pred));
2689 return;
2690 }
2691
2692 if (const auto *Ex = dyn_cast<Expr>(Val: Condition))
2693 Condition = Ex->IgnoreParens();
2694
2695 Condition = ResolveCondition(Condition, B: getCurrBlock());
2696 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
2697 Condition->getBeginLoc(),
2698 "Error evaluating branch");
2699
2700 ExplodedNodeSet CheckersOutSet;
2701 getCheckerManager().runCheckersForBranchCondition(condition: Condition, Dst&: CheckersOutSet,
2702 Pred, Eng&: *this);
2703 // We generated only sinks.
2704 if (CheckersOutSet.empty())
2705 return;
2706
2707 for (ExplodedNode *PredN : CheckersOutSet) {
2708 ProgramStateRef PrevState = PredN->getState();
2709
2710 ProgramStateRef StTrue = PrevState, StFalse = PrevState;
2711 if (const auto KnownCondValueAssumption = assumeCondition(ConditionStmt: Condition, N: PredN))
2712 std::tie(args&: StTrue, args&: StFalse) = *KnownCondValueAssumption;
2713
2714 if (StTrue && StFalse)
2715 assert(!isa<ObjCForCollectionStmt>(Condition));
2716
2717 // We want to ensure consistent behavior between `eagerly-assume=false`,
2718 // when the state split is always performed by the `assumeCondition()`
2719 // call within this function and `eagerly-assume=true` (the default), when
2720 // some conditions (comparison operators, unary negation) can trigger a
2721 // state split before this callback. There are some contrived corner cases
2722 // that behave differently with and without `eagerly-assume`, but I don't
2723 // know about an example that could plausibly appear in "real" code.
2724 bool BothFeasible =
2725 (StTrue && StFalse) ||
2726 didEagerlyAssumeBifurcateAt(State: PrevState, Ex: dyn_cast<Expr>(Val: Condition));
2727
2728 if (StTrue) {
2729 // In a loop, if both branches are feasible (i.e. the analyzer doesn't
2730 // understand the loop condition) and two iterations have already been
2731 // completed, then don't assume a third iteration because it is a
2732 // redundant execution path (unlikely to be different from earlier loop
2733 // exits) and can cause false positives if e.g. the loop iterates over a
2734 // two-element structure with an opaque condition.
2735 //
2736 // The iteration count "2" is hardcoded because it's the natural limit:
2737 // * the fact that the programmer wrote a loop (and not just an `if`)
2738 // implies that they thought that the loop body might be executed twice;
2739 // * however, there are situations where the programmer knows that there
2740 // are at most two iterations but writes a loop that appears to be
2741 // generic, because there is no special syntax for "loop with at most
2742 // two iterations". (This pattern is common in FFMPEG and appears in
2743 // many other projects as well.)
2744 bool CompletedTwoIterations = IterationsCompletedInLoop.value_or(u: 0) >= 2;
2745 bool SkipTrueBranch = BothFeasible && CompletedTwoIterations;
2746
2747 // FIXME: This "don't assume third iteration" heuristic partially
2748 // conflicts with the widen-loop analysis option (which is off by
2749 // default). If we intend to support and stabilize the loop widening,
2750 // we must ensure that it 'plays nicely' with this logic.
2751 if (!SkipTrueBranch || AMgr.options.ShouldWidenLoops) {
2752 if (DstT) {
2753 BlockEdge BE(getCurrBlock(), DstT, SF);
2754 Dst.insert(N: Engine.makeNode(Loc: BE, State: StTrue, Pred: PredN));
2755 }
2756 } else if (!AMgr.options.InlineFunctionsWithAmbiguousLoops) {
2757 // FIXME: There is an ancient and arbitrary heuristic in
2758 // `ExprEngine::processCFGBlockEntrance` which prevents all further
2759 // inlining of a function if it finds an execution path within that
2760 // function which reaches the `MaxBlockVisitOnPath` limit (a/k/a
2761 // `analyzer-max-loop`, by default four iterations in a loop). Adding
2762 // this "don't assume third iteration" logic significantly increased
2763 // the analysis runtime on some inputs because less functions were
2764 // arbitrarily excluded from being inlined, so more entry points used
2765 // up their full allocated budget. As a hacky compensation for this,
2766 // here we apply the "should not inline" mark in cases when the loop
2767 // could potentially reach the `MaxBlockVisitOnPath` limit without the
2768 // "don't assume third iteration" logic. This slightly overcompensates
2769 // (activates if the third iteration can be entered, and will not
2770 // recognize cases where the fourth iteration would't be completed), but
2771 // should be good enough for practical purposes.
2772 if (!SF->inTopFrame()) {
2773 Engine.FunctionSummaries->markShouldNotInline(D: SF->getDecl());
2774 }
2775 }
2776 }
2777
2778 if (StFalse) {
2779 // In a loop, if both branches are feasible (i.e. the analyzer doesn't
2780 // understand the loop condition), we are before the first iteration and
2781 // the analyzer option `assume-at-least-one-iteration` is set to `true`,
2782 // then avoid creating the execution path where the loop is skipped.
2783 //
2784 // In some situations this "loop is skipped" execution path is an
2785 // important corner case that may evade the notice of the developer and
2786 // hide significant bugs -- however, there are also many situations where
2787 // it's guaranteed that at least one iteration will happen (e.g. some
2788 // data structure is always nonempty), but the analyzer cannot realize
2789 // this and will produce false positives when it assumes that the loop is
2790 // skipped.
2791 bool BeforeFirstIteration = IterationsCompletedInLoop == std::optional{0};
2792 bool SkipFalseBranch = BothFeasible && BeforeFirstIteration &&
2793 AMgr.options.ShouldAssumeAtLeastOneIteration;
2794 if (!SkipFalseBranch && DstF) {
2795 BlockEdge BE(getCurrBlock(), DstF, SF);
2796 Dst.insert(N: Engine.makeNode(Loc: BE, State: StFalse, Pred: PredN));
2797 }
2798 }
2799 }
2800}
2801
2802/// The GDM component containing the set of global variables which have been
2803/// previously initialized with explicit initializers.
2804REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,
2805 llvm::ImmutableSet<const VarDecl *>)
2806
2807void ExprEngine::processStaticInitializer(const DeclStmt *DS,
2808 ExplodedNode *Pred,
2809 ExplodedNodeSet &Dst,
2810 const CFGBlock *DstT,
2811 const CFGBlock *DstF) {
2812 const auto *VD = cast<VarDecl>(Val: DS->getSingleDecl());
2813 ProgramStateRef State = Pred->getState();
2814 bool InitHasRun = State->contains<InitializedGlobalsSet>(key: VD);
2815 if (!InitHasRun)
2816 State = State->add<InitializedGlobalsSet>(K: VD);
2817
2818 if (const CFGBlock *DstBlock = InitHasRun ? DstT : DstF) {
2819 BlockEdge BE(getCurrBlock(), DstBlock, Pred->getStackFrame());
2820 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred));
2821 }
2822}
2823
2824/// processIndirectGoto - Called by CoreEngine. Used to generate successor
2825/// nodes by processing the 'effects' of a computed goto jump.
2826void ExprEngine::processIndirectGoto(ExplodedNodeSet &Dst, const Expr *Tgt,
2827 const CFGBlock *Dispatch,
2828 ExplodedNode *Pred) {
2829 ProgramStateRef State = Pred->getState();
2830 SVal V = State->getSVal(E: Tgt, SF: getCurrStackFrame());
2831
2832 // We cannot dispatch anywhere if the label is undefined, NULL or some other
2833 // concrete number.
2834 // FIXME: Emit a warning in this situation.
2835 if (isa<UndefinedVal, loc::ConcreteInt>(Val: V))
2836 return;
2837
2838 // If 'V' is the address of a concrete goto label (on this execution path),
2839 // then only transition along the edge to that label.
2840 // FIXME: Implement dispatch for symbolic pointers, utilizing information
2841 // that they are equal or not equal to pointers to a certain goto label.
2842 const LabelDecl *L = nullptr;
2843 if (auto LV = V.getAs<loc::GotoLabel>())
2844 L = LV->getLabel();
2845
2846 // Dispatch to the label 'L' or to all labels if 'L' is null.
2847 for (const CFGBlock *Succ : Dispatch->succs()) {
2848 if (!L || cast<LabelStmt>(Val: Succ->getLabel())->getDecl() == L) {
2849 // FIXME: If 'V' was a symbolic value, then record that on this execution
2850 // path it is equal to the address of the label leading to 'Succ'.
2851 BlockEdge BE(getCurrBlock(), Succ, Pred->getStackFrame());
2852 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred));
2853 }
2854 }
2855}
2856
2857void ExprEngine::processBeginOfFunction(ExplodedNode *Pred,
2858 ExplodedNodeSet &Dst,
2859 const BlockEdge &L) {
2860 getCheckerManager().runCheckersForBeginFunction(Dst, L, Pred, Eng&: *this);
2861}
2862
2863/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
2864/// nodes when the control reaches the end of a function.
2865void ExprEngine::processEndOfFunction(ExplodedNode *Pred,
2866 const ReturnStmt *RS) {
2867 ProgramStateRef State = Pred->getState();
2868
2869 if (!Pred->getStackFrame()->inTopFrame())
2870 State = finishArgumentConstruction(
2871 State, Call: *getStateManager().getCallEventManager().getCaller(
2872 CalleeSF: Pred->getStackFrame(), State: Pred->getState()));
2873
2874 // FIXME: We currently cannot assert that temporaries are clear, because
2875 // lifetime extended temporaries are not always modelled correctly. In some
2876 // cases when we materialize the temporary, we do
2877 // createTemporaryRegionIfNeeded(), and the region changes, and also the
2878 // respective destructor becomes automatic from temporary. So for now clean up
2879 // the state manually before asserting. Ideally, this braced block of code
2880 // should go away.
2881 {
2882 const StackFrame *FromSF = Pred->getStackFrame();
2883 const StackFrame *ToSF = FromSF->getParent();
2884 const StackFrame *SF = FromSF;
2885 while (SF != ToSF) {
2886 assert(SF && "ToSF must be a parent of FromSF!");
2887 for (auto I : State->get<ObjectsUnderConstruction>())
2888 if (I.first.getStackFrame() == SF) {
2889 // The comment above only pardons us for not cleaning up a
2890 // temporary destructor. If any other statements are found here,
2891 // it must be a separate problem.
2892 assert(I.first.getItem().getKind() ==
2893 ConstructionContextItem::TemporaryDestructorKind ||
2894 I.first.getItem().getKind() ==
2895 ConstructionContextItem::ElidedDestructorKind);
2896 State = State->remove<ObjectsUnderConstruction>(K: I.first);
2897 }
2898 SF = SF->getParent();
2899 }
2900 }
2901
2902 // Perform the transition with cleanups.
2903 if (State != Pred->getState()) {
2904 Pred = Engine.makeNode(Loc: Pred->getLocation(), State, Pred);
2905 if (!Pred) {
2906 // The node with clean temporaries already exists. We might have reached
2907 // it on a path on which we initialize different temporaries.
2908 return;
2909 }
2910 }
2911
2912 assert(areAllObjectsFullyConstructed(Pred->getState(), Pred->getStackFrame(),
2913 Pred->getStackFrame()->getParent()));
2914 ExplodedNodeSet Dst;
2915 if (Pred->getStackFrame()->inTopFrame()) {
2916 // Remove dead symbols.
2917 ExplodedNodeSet AfterRemovedDead;
2918 removeDeadOnEndOfFunction(Pred, Dst&: AfterRemovedDead);
2919
2920 // Notify checkers.
2921 for (const auto I : AfterRemovedDead)
2922 getCheckerManager().runCheckersForEndFunction(Dst, Pred: I, Eng&: *this, RS);
2923 } else {
2924 getCheckerManager().runCheckersForEndFunction(Dst, Pred, Eng&: *this, RS);
2925 }
2926
2927 Engine.enqueueEndOfFunction(Set&: Dst, RS);
2928}
2929
2930/// ProcessSwitch - Called by CoreEngine. Used to generate successor
2931/// nodes by processing the 'effects' of a switch statement.
2932void ExprEngine::processSwitch(const SwitchStmt *Switch, ExplodedNode *Pred,
2933 ExplodedNodeSet &Dst) {
2934 const ASTContext &ACtx = getContext();
2935 const StackFrame *SF = Pred->getStackFrame();
2936 const Expr *Condition = Switch->getCond();
2937
2938 // The block that is terminated by the switch statement.
2939 const CFGBlock *SwitchBlock = getCurrBlock();
2940 // Note that successors may be null if they are pruned as unreachable.
2941 assert(SwitchBlock->succ_size() && "Switch must have at least one successor");
2942 // The reversed iteration order is present since the beginning, when in 2008
2943 // commit 80ebc1d1c95704b0ff0386b3a3cbc8b3ff960654 added support for handling
2944 // switch statements. I don't see any advantage over regular forward
2945 // iteration -- but switching the order would perturb the insertion order of
2946 // the work list and therefore the analysis results.
2947 llvm::iterator_range<CFGBlock::const_succ_reverse_iterator> CaseBlocks(
2948 SwitchBlock->succ_rbegin() + 1, SwitchBlock->succ_rend());
2949 const CFGBlock *DefaultBlock = *SwitchBlock->succ_rbegin();
2950
2951 ExplodedNodeSet CheckersOutSet;
2952
2953 getCheckerManager().runCheckersForBranchCondition(
2954 condition: Condition->IgnoreParens(), Dst&: CheckersOutSet, Pred, Eng&: *this);
2955
2956 for (ExplodedNode *Node : CheckersOutSet) {
2957 ProgramStateRef State = Node->getState();
2958
2959 SVal CondV = State->getSVal(E: Condition, SF);
2960 if (CondV.isUndef()) {
2961 // This can only happen if core.uninitialized.Branch is disabled.
2962 continue;
2963 }
2964 std::optional<NonLoc> CondNL = CondV.getAs<NonLoc>();
2965
2966 for (const CFGBlock *CaseBlock : CaseBlocks) {
2967 // Successor may be pruned out during CFG construction.
2968 if (!CaseBlock)
2969 continue;
2970
2971 const CaseStmt *Case = cast<CaseStmt>(Val: CaseBlock->getLabel());
2972
2973 // Evaluate the LHS of the case value.
2974 llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(Ctx: ACtx);
2975 assert(V1.getBitWidth() ==
2976 getContext().getIntWidth(Condition->getType()));
2977
2978 // Get the RHS of the case, if it exists.
2979 llvm::APSInt V2;
2980 if (const Expr *E = Case->getRHS())
2981 V2 = E->EvaluateKnownConstInt(Ctx: ACtx);
2982 else
2983 V2 = V1;
2984
2985 ProgramStateRef StateMatching;
2986 if (CondNL) {
2987 // Split the state: this "case:" matches / does not match.
2988 std::tie(args&: StateMatching, args&: State) =
2989 State->assumeInclusiveRange(Val: *CondNL, From: V1, To: V2);
2990 } else {
2991 // The switch condition is UnknownVal, so we enter each "case:" without
2992 // any state update.
2993 StateMatching = State;
2994 }
2995
2996 if (StateMatching) {
2997 BlockEdge BE(SwitchBlock, CaseBlock, SF);
2998 Dst.insert(N: Engine.makeNode(Loc: BE, State: StateMatching, Pred: Node));
2999 }
3000
3001 // If _not_ entering the current case is infeasible, then we are done
3002 // with processing the paths through the current Node.
3003 if (!State)
3004 break;
3005 }
3006 if (!State)
3007 continue;
3008
3009 // The default block may be null if it is "optimized out" by CFG creation.
3010 if (!DefaultBlock)
3011 continue;
3012
3013 // If we have switch(enum value), the default branch is not
3014 // feasible if all of the enum constants not covered by 'case:' statements
3015 // are not feasible values for the switch condition.
3016 //
3017 // Note that this isn't as accurate as it could be. Even if there isn't
3018 // a case for a particular enum value as long as that enum value isn't
3019 // feasible then it shouldn't be considered for making 'default:' reachable.
3020 if (Condition->IgnoreParenImpCasts()->getType()->isEnumeralType()) {
3021 if (Switch->isAllEnumCasesCovered())
3022 continue;
3023 }
3024
3025 BlockEdge BE(SwitchBlock, DefaultBlock, SF);
3026 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred: Node));
3027 }
3028}
3029
3030//===----------------------------------------------------------------------===//
3031// Transfer functions: Loads and stores.
3032//===----------------------------------------------------------------------===//
3033
3034void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
3035 ExplodedNode *Pred,
3036 ExplodedNodeSet &Dst) {
3037 ProgramStateRef state = Pred->getState();
3038 const StackFrame *SF = Pred->getStackFrame();
3039
3040 auto resolveAsLambdaCapturedVar =
3041 [&](const ValueDecl *VD) -> std::optional<std::pair<SVal, QualType>> {
3042 const auto *MD = dyn_cast<CXXMethodDecl>(Val: SF->getDecl());
3043 const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Val: Ex);
3044 if (AMgr.options.ShouldInlineLambdas && DeclRefEx &&
3045 DeclRefEx->refersToEnclosingVariableOrCapture() && MD &&
3046 MD->getParent()->isLambda()) {
3047 // Lookup the field of the lambda.
3048 const CXXRecordDecl *CXXRec = MD->getParent();
3049 llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
3050 FieldDecl *LambdaThisCaptureField;
3051 CXXRec->getCaptureFields(Captures&: LambdaCaptureFields, ThisCapture&: LambdaThisCaptureField);
3052
3053 // Sema follows a sequence of complex rules to determine whether the
3054 // variable should be captured.
3055 if (const FieldDecl *FD = LambdaCaptureFields[VD]) {
3056 Loc CXXThis = svalBuilder.getCXXThis(D: MD, SF);
3057 SVal CXXThisVal = state->getSVal(LV: CXXThis);
3058 return std::make_pair(x: state->getLValue(decl: FD, Base: CXXThisVal), y: FD->getType());
3059 }
3060 }
3061
3062 return std::nullopt;
3063 };
3064
3065 if (const auto *VD = dyn_cast<VarDecl>(Val: D)) {
3066 // C permits "extern void v", and if you cast the address to a valid type,
3067 // you can even do things with it. We simply pretend
3068 assert(Ex->isGLValue() || VD->getType()->isVoidType());
3069 std::optional<std::pair<SVal, QualType>> VInfo =
3070 resolveAsLambdaCapturedVar(VD);
3071
3072 if (!VInfo)
3073 VInfo = std::make_pair(x: state->getLValue(VD, SF), y: VD->getType());
3074
3075 SVal V = VInfo->first;
3076 bool IsReference = VInfo->second->isReferenceType();
3077
3078 // For references, the 'lvalue' is the pointer address stored in the
3079 // reference region.
3080 if (IsReference) {
3081 if (const MemRegion *R = V.getAsRegion())
3082 V = state->getSVal(R);
3083 else
3084 V = UnknownVal();
3085 }
3086
3087 Dst.insert(
3088 N: Engine.makeNodeWithBinding(Pred, E: Ex, V, K: ProgramPoint::PostLValueKind));
3089 return;
3090 }
3091 if (const auto *ED = dyn_cast<EnumConstantDecl>(Val: D)) {
3092 assert(!Ex->isGLValue());
3093 SVal V = svalBuilder.makeIntVal(integer: ED->getInitVal());
3094 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: Ex, V));
3095 return;
3096 }
3097 if (const auto *FD = dyn_cast<FunctionDecl>(Val: D)) {
3098 SVal V = svalBuilder.getFunctionPointer(func: FD);
3099 Dst.insert(
3100 N: Engine.makeNodeWithBinding(Pred, E: Ex, V, K: ProgramPoint::PostLValueKind));
3101 return;
3102 }
3103 if (isa<FieldDecl, IndirectFieldDecl>(Val: D)) {
3104 // Delegate all work related to pointer to members to the surrounding
3105 // operator&.
3106 Dst.insert(N: Pred);
3107 return;
3108 }
3109 if (const auto *BD = dyn_cast<BindingDecl>(Val: D)) {
3110 // Handle structured bindings captured by lambda.
3111 if (std::optional<std::pair<SVal, QualType>> VInfo =
3112 resolveAsLambdaCapturedVar(BD)) {
3113 auto [V, T] = VInfo.value();
3114
3115 if (T->isReferenceType()) {
3116 if (const MemRegion *R = V.getAsRegion())
3117 V = state->getSVal(R);
3118 else
3119 V = UnknownVal();
3120 }
3121
3122 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: Ex, V,
3123 K: ProgramPoint::PostLValueKind));
3124 return;
3125 }
3126
3127 const auto *DD = cast<DecompositionDecl>(Val: BD->getDecomposedDecl());
3128
3129 SVal Base = state->getLValue(VD: DD, SF);
3130 if (DD->getType()->isReferenceType()) {
3131 if (const MemRegion *R = Base.getAsRegion())
3132 Base = state->getSVal(R);
3133 else
3134 Base = UnknownVal();
3135 }
3136
3137 SVal V = UnknownVal();
3138
3139 // Handle binding to data members
3140 if (const auto *ME = dyn_cast<MemberExpr>(Val: BD->getBinding())) {
3141 const auto *Field = cast<FieldDecl>(Val: ME->getMemberDecl());
3142 V = state->getLValue(decl: Field, Base);
3143 }
3144 // Handle binding to arrays
3145 else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Val: BD->getBinding())) {
3146 SVal Idx = state->getSVal(E: ASE->getIdx(), SF);
3147
3148 // Note: the index of an element in a structured binding is automatically
3149 // created and it is a unique identifier of the specific element. Thus it
3150 // cannot be a value that varies at runtime.
3151 assert(Idx.isConstant() && "BindingDecl array index is not a constant!");
3152
3153 V = state->getLValue(ElementType: BD->getType(), Idx, Base);
3154 }
3155 // Handle binding to tuple-like structures
3156 else if (const auto *HV = BD->getHoldingVar()) {
3157 V = state->getLValue(VD: HV, SF);
3158
3159 if (HV->getType()->isReferenceType()) {
3160 if (const MemRegion *R = V.getAsRegion())
3161 V = state->getSVal(R);
3162 else
3163 V = UnknownVal();
3164 }
3165 } else
3166 llvm_unreachable("An unknown case of structured binding encountered!");
3167
3168 // In case of tuple-like types the references are already handled, so we
3169 // don't want to handle them again.
3170 if (BD->getType()->isReferenceType() && !BD->getHoldingVar()) {
3171 if (const MemRegion *R = V.getAsRegion())
3172 V = state->getSVal(R);
3173 else
3174 V = UnknownVal();
3175 }
3176
3177 Dst.insert(
3178 N: Engine.makeNodeWithBinding(Pred, E: Ex, V, K: ProgramPoint::PostLValueKind));
3179 return;
3180 }
3181
3182 if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(Val: D)) {
3183 // FIXME: We should meaningfully implement this.
3184 (void)TPO;
3185 Dst.insert(N: Pred);
3186 return;
3187 }
3188
3189 llvm_unreachable("Support for this Decl not implemented.");
3190}
3191
3192/// VisitArrayInitLoopExpr - Transfer function for array init loop.
3193void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex,
3194 ExplodedNode *Pred,
3195 ExplodedNodeSet &Dst) {
3196 const Expr *Arr = Ex->getCommonExpr()->getSourceExpr();
3197
3198 ExplodedNodeSet CheckerPreStmt;
3199 getCheckerManager().runCheckersForPreStmt(Dst&: CheckerPreStmt, Src: Pred, S: Ex, Eng&: *this);
3200
3201 ExplodedNodeSet EvalSet;
3202 if (isa<CXXConstructExpr>(Val: Ex->getSubExpr())) {
3203 // The constructor visitor has already handled everything, so let's skip
3204 // forward to PostStmt handling by clearing the range of the 'for' loop.
3205 EvalSet.insert(S: CheckerPreStmt);
3206 CheckerPreStmt.clear();
3207 }
3208
3209 for (auto *Node : CheckerPreStmt) {
3210 const StackFrame *SF = Node->getStackFrame();
3211 ProgramStateRef state = Node->getState();
3212
3213 SVal Base = UnknownVal();
3214
3215 // As in case of this expression the sub-expressions are not visited by any
3216 // other transfer functions, they are handled by matching their AST.
3217
3218 // Case of implicit copy or move ctor of object with array member
3219 //
3220 // Note: ExprEngine::VisitMemberExpr is not able to bind the array to the
3221 // environment.
3222 //
3223 // struct S {
3224 // int arr[2];
3225 // };
3226 //
3227 //
3228 // S a;
3229 // S b = a;
3230 //
3231 // The AST in case of a *copy constructor* looks like this:
3232 // ArrayInitLoopExpr
3233 // |-OpaqueValueExpr
3234 // | `-MemberExpr <-- match this
3235 // | `-DeclRefExpr
3236 // ` ...
3237 //
3238 //
3239 // S c;
3240 // S d = std::move(d);
3241 //
3242 // In case of a *move constructor* the resulting AST looks like:
3243 // ArrayInitLoopExpr
3244 // |-OpaqueValueExpr
3245 // | `-MemberExpr <-- match this first
3246 // | `-CXXStaticCastExpr <-- match this after
3247 // | `-DeclRefExpr
3248 // ` ...
3249 if (const auto *ME = dyn_cast<MemberExpr>(Val: Arr)) {
3250 Expr *MEBase = ME->getBase();
3251
3252 // Move ctor
3253 if (auto CXXSCE = dyn_cast<CXXStaticCastExpr>(Val: MEBase)) {
3254 MEBase = CXXSCE->getSubExpr();
3255 }
3256
3257 auto ObjDeclExpr = cast<DeclRefExpr>(Val: MEBase);
3258 SVal Obj = state->getLValue(VD: cast<VarDecl>(Val: ObjDeclExpr->getDecl()), SF);
3259
3260 Base = state->getLValue(decl: cast<FieldDecl>(Val: ME->getMemberDecl()), Base: Obj);
3261 }
3262
3263 // Case of lambda capture and decomposition declaration
3264 //
3265 // int arr[2];
3266 //
3267 // [arr]{ int a = arr[0]; }();
3268 // auto[a, b] = arr;
3269 //
3270 // In both of these cases the AST looks like the following:
3271 // ArrayInitLoopExpr
3272 // |-OpaqueValueExpr
3273 // | `-DeclRefExpr <-- match this
3274 // ` ...
3275 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Val: Arr))
3276 Base = state->getLValue(VD: cast<VarDecl>(Val: DRE->getDecl()), SF);
3277
3278 // Create a lazy compound value to the original array
3279 if (const MemRegion *R = Base.getAsRegion())
3280 Base = state->getSVal(R);
3281 else
3282 Base = UnknownVal();
3283
3284 EvalSet.insert(N: Engine.makeNodeWithBinding(Pred: Node, E: Ex, V: Base));
3285 }
3286
3287 getCheckerManager().runCheckersForPostStmt(Dst, Src: EvalSet, S: Ex, Eng&: *this);
3288}
3289
3290/// VisitArraySubscriptExpr - Transfer function for array accesses
3291void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A,
3292 ExplodedNode *Pred,
3293 ExplodedNodeSet &Dst){
3294 const Expr *Base = A->getBase()->IgnoreParens();
3295 const Expr *Idx = A->getIdx()->IgnoreParens();
3296
3297 ExplodedNodeSet CheckerPreStmt;
3298 getCheckerManager().runCheckersForPreStmt(Dst&: CheckerPreStmt, Src: Pred, S: A, Eng&: *this);
3299
3300 ExplodedNodeSet EvalSet;
3301
3302 bool IsVectorType = A->getBase()->getType()->isVectorType();
3303
3304 // The "like" case is for situations where C standard prohibits the type to
3305 // be an lvalue, e.g. taking the address of a subscript of an expression of
3306 // type "void *".
3307 bool IsGLValueLike = A->isGLValue() ||
3308 (A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus);
3309
3310 for (auto *Node : CheckerPreStmt) {
3311 const StackFrame *SF = Node->getStackFrame();
3312 ProgramStateRef state = Node->getState();
3313
3314 if (IsGLValueLike) {
3315 QualType T = A->getType();
3316
3317 // One of the forbidden LValue types! We still need to have sensible
3318 // symbolic locations to represent this stuff. Note that arithmetic on
3319 // void pointers is a GCC extension.
3320 if (T->isVoidType())
3321 T = getContext().CharTy;
3322
3323 SVal V = state->getLValue(ElementType: T, Idx: state->getSVal(E: Idx, SF),
3324 Base: state->getSVal(E: Base, SF));
3325 EvalSet.insert(
3326 N: Engine.makeNodeWithBinding(Pred: Node, E: A, V, K: ProgramPoint::PostLValueKind));
3327 } else if (IsVectorType) {
3328 // FIXME: non-glvalue vector reads are not modelled.
3329 EvalSet.insert(N: Engine.makePostStmtNode(S: A, State: state, Pred: Node));
3330 } else {
3331 llvm_unreachable("Array subscript should be an lValue when not \
3332a vector and not a forbidden lvalue type");
3333 }
3334 }
3335
3336 getCheckerManager().runCheckersForPostStmt(Dst, Src: EvalSet, S: A, Eng&: *this);
3337}
3338
3339/// VisitMemberExpr - Transfer function for member expressions.
3340void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
3341 ExplodedNodeSet &Dst) {
3342 // FIXME: Prechecks eventually go in ::Visit().
3343 ExplodedNodeSet CheckedSet;
3344 getCheckerManager().runCheckersForPreStmt(Dst&: CheckedSet, Src: Pred, S: M, Eng&: *this);
3345
3346 ExplodedNodeSet EvalSet;
3347 ValueDecl *Member = M->getMemberDecl();
3348
3349 // Handle static member variables and enum constants accessed via
3350 // member syntax.
3351 if (isa<VarDecl, EnumConstantDecl>(Val: Member)) {
3352 for (const auto I : CheckedSet)
3353 VisitCommonDeclRefExpr(Ex: M, D: Member, Pred: I, Dst&: EvalSet);
3354 } else {
3355 ExplodedNodeSet Tmp;
3356
3357 for (const auto I : CheckedSet) {
3358 ProgramStateRef state = I->getState();
3359 const StackFrame *SF = I->getStackFrame();
3360 Expr *BaseExpr = M->getBase();
3361
3362 // Handle C++ method calls.
3363 if (const auto *MD = dyn_cast<CXXMethodDecl>(Val: Member)) {
3364 if (MD->isImplicitObjectMemberFunction())
3365 state = createTemporaryRegionIfNeeded(State: state, SF, InitWithAdjustments: BaseExpr);
3366
3367 SVal MDVal = svalBuilder.getFunctionPointer(func: MD);
3368
3369 EvalSet.insert(N: Engine.makeNodeWithBinding(Pred: I, E: M, V: MDVal, State: state));
3370 continue;
3371 }
3372
3373 // Handle regular struct fields / member variables.
3374 const SubRegion *MR = nullptr;
3375 state = createTemporaryRegionIfNeeded(State: state, SF, InitWithAdjustments: BaseExpr,
3376 /*Result=*/nullptr,
3377 /*OutRegionWithAdjustments=*/&MR);
3378 SVal baseExprVal =
3379 MR ? loc::MemRegionVal(MR) : state->getSVal(E: BaseExpr, SF);
3380
3381 // FIXME: Copied from RegionStoreManager::bind()
3382 if (const auto *SR =
3383 dyn_cast_or_null<SymbolicRegion>(Val: baseExprVal.getAsRegion())) {
3384 QualType T = SR->getPointeeStaticType();
3385 baseExprVal =
3386 loc::MemRegionVal(getStoreManager().GetElementZeroRegion(R: SR, T));
3387 }
3388
3389 const auto *field = cast<FieldDecl>(Val: Member);
3390 SVal L = state->getLValue(decl: field, Base: baseExprVal);
3391
3392 if (M->isGLValue() || M->getType()->isArrayType()) {
3393 // We special-case rvalues of array type because the analyzer cannot
3394 // reason about them, since we expect all regions to be wrapped in Locs.
3395 // We instead treat these as lvalues and assume that they will decay to
3396 // pointers as soon as they are used.
3397 if (!M->isGLValue()) {
3398 assert(M->getType()->isArrayType());
3399 const auto *PE =
3400 dyn_cast<ImplicitCastExpr>(Val: I->getParentMap().getParentIgnoreParens(S: M));
3401 if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) {
3402 llvm_unreachable("should always be wrapped in ArrayToPointerDecay");
3403 }
3404 }
3405
3406 if (field->getType()->isReferenceType()) {
3407 if (const MemRegion *R = L.getAsRegion())
3408 L = state->getSVal(R);
3409 else
3410 L = UnknownVal();
3411 }
3412
3413 EvalSet.insert(N: Engine.makeNodeWithBinding(
3414 Pred: I, E: M, V: L, State: state, K: ProgramPoint::PostLValueKind));
3415 } else {
3416 // FIXME: When evalLoad no longer uses NodeBuilders, eliminate Tmp and
3417 // pass EvalSet as the first argument of evalLoad.
3418 evalLoad(Dst&: Tmp, NodeEx: M, BoundExpr: M, Pred: I, St: state, location: L);
3419 EvalSet.insert(S: Tmp);
3420 }
3421 }
3422 }
3423
3424 getCheckerManager().runCheckersForPostStmt(Dst, Src: EvalSet, S: M, Eng&: *this);
3425}
3426
3427void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
3428 ExplodedNodeSet &Dst) {
3429 ExplodedNodeSet AfterPreSet;
3430 getCheckerManager().runCheckersForPreStmt(Dst&: AfterPreSet, Src: Pred, S: AE, Eng&: *this);
3431
3432 // For now, treat all the arguments to C11 atomics as escaping.
3433 // FIXME: Ideally we should model the behavior of the atomics precisely here.
3434
3435 ExplodedNodeSet AfterInvalidateSet;
3436
3437 for (const auto I : AfterPreSet) {
3438 ProgramStateRef State = I->getState();
3439 const StackFrame *SF = I->getStackFrame();
3440
3441 SmallVector<SVal, 8> ValuesToInvalidate;
3442 for (const Stmt *SubExpr : AE->children()) {
3443 SVal SubExprVal = State->getSVal(E: cast<Expr>(Val: SubExpr), SF);
3444 ValuesToInvalidate.push_back(Elt: SubExprVal);
3445 }
3446
3447 State = State->invalidateRegions(Values: ValuesToInvalidate, Elem: getCFGElementRef(),
3448 BlockCount: getNumVisitedCurrent(), SF,
3449 /*CausedByPointerEscape*/ CausesPointerEscape: true,
3450 /*Symbols=*/IS: nullptr);
3451
3452 AfterInvalidateSet.insert(
3453 N: Engine.makeNodeWithBinding(Pred: I, E: AE, V: UnknownVal(), State));
3454 }
3455
3456 getCheckerManager().runCheckersForPostStmt(Dst, Src: AfterInvalidateSet, S: AE, Eng&: *this);
3457}
3458
3459// A value escapes in four possible cases:
3460// (1) We are binding to something that is not a memory region.
3461// (2) We are binding to a MemRegion that does not have stack storage.
3462// (3) We are binding to a top-level parameter region with a non-trivial
3463// destructor. We won't see the destructor during analysis, but it's there.
3464// (4) We are binding to a MemRegion with stack storage that the store
3465// does not understand.
3466ProgramStateRef ExprEngine::processPointerEscapedOnBind(
3467 ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals,
3468 const StackFrame *SF, PointerEscapeKind Kind, const CallEvent *Call) {
3469 SmallVector<SVal, 8> Escaped;
3470 for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
3471 // Cases (1) and (2).
3472 const MemRegion *MR = LocAndVal.first.getAsRegion();
3473 const MemSpaceRegion *Space = MR ? MR->getMemorySpace(State) : nullptr;
3474 if (!MR || !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(Val: Space)) {
3475 Escaped.push_back(Elt: LocAndVal.second);
3476 continue;
3477 }
3478
3479 // Case (3).
3480 if (const auto *VR = dyn_cast<VarRegion>(Val: MR->getBaseRegion()))
3481 if (isa<StackArgumentsSpaceRegion>(Val: Space) &&
3482 VR->getStackFrame()->inTopFrame())
3483 if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
3484 if (!RD->hasTrivialDestructor()) {
3485 Escaped.push_back(Elt: LocAndVal.second);
3486 continue;
3487 }
3488
3489 // Case (4): in order to test that, generate a new state with the binding
3490 // added. If it is the same state, then it escapes (since the store cannot
3491 // represent the binding).
3492 // Do this only if we know that the store is not supposed to generate the
3493 // same state.
3494 SVal StoredVal = State->getSVal(R: MR);
3495 if (StoredVal != LocAndVal.second)
3496 if (State ==
3497 (State->bindLoc(location: loc::MemRegionVal(MR), V: LocAndVal.second, SF)))
3498 Escaped.push_back(Elt: LocAndVal.second);
3499 }
3500
3501 if (Escaped.empty())
3502 return State;
3503
3504 return escapeValues(State, Vs: Escaped, K: Kind, Call);
3505}
3506
3507ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
3508 SVal Loc, SVal Val,
3509 const StackFrame *SF) {
3510 std::pair<SVal, SVal> LocAndVal(Loc, Val);
3511 return processPointerEscapedOnBind(State, LocAndVals: LocAndVal, SF, Kind: PSK_EscapeOnBind,
3512 Call: nullptr);
3513}
3514
3515ProgramStateRef
3516ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
3517 const InvalidatedSymbols *Invalidated,
3518 ArrayRef<const MemRegion *> ExplicitRegions,
3519 const CallEvent *Call,
3520 RegionAndSymbolInvalidationTraits &ITraits) {
3521 if (!Invalidated || Invalidated->empty())
3522 return State;
3523
3524 if (!Call)
3525 return getCheckerManager().runCheckersForPointerEscape(State,
3526 Escaped: *Invalidated,
3527 Call: nullptr,
3528 Kind: PSK_EscapeOther,
3529 ITraits: &ITraits);
3530
3531 // If the symbols were invalidated by a call, we want to find out which ones
3532 // were invalidated directly due to being arguments to the call.
3533 InvalidatedSymbols SymbolsDirectlyInvalidated;
3534 for (const auto I : ExplicitRegions) {
3535 if (const SymbolicRegion *R = I->StripCasts()->getAs<SymbolicRegion>())
3536 SymbolsDirectlyInvalidated.insert(V: R->getSymbol());
3537 }
3538
3539 InvalidatedSymbols SymbolsIndirectlyInvalidated;
3540 for (const auto &sym : *Invalidated) {
3541 if (SymbolsDirectlyInvalidated.count(V: sym))
3542 continue;
3543 SymbolsIndirectlyInvalidated.insert(V: sym);
3544 }
3545
3546 if (!SymbolsDirectlyInvalidated.empty())
3547 State = getCheckerManager().runCheckersForPointerEscape(State,
3548 Escaped: SymbolsDirectlyInvalidated, Call, Kind: PSK_DirectEscapeOnCall, ITraits: &ITraits);
3549
3550 // Notify about the symbols that get indirectly invalidated by the call.
3551 if (!SymbolsIndirectlyInvalidated.empty())
3552 State = getCheckerManager().runCheckersForPointerEscape(State,
3553 Escaped: SymbolsIndirectlyInvalidated, Call, Kind: PSK_IndirectEscapeOnCall, ITraits: &ITraits);
3554
3555 return State;
3556}
3557
3558/// evalBind - Handle the semantics of binding a value to a specific location.
3559/// This method is used by evalStore, VisitDeclStmt, and others.
3560void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
3561 ExplodedNode *Pred, SVal Location, SVal Val,
3562 bool AtDeclInit, const ProgramPoint *PP) {
3563
3564 // It may be a Loc, UnknownVal or perhaps UndefinedVal.
3565 assert(!isa<NonLoc>(Location) && "evalBind location should not be NonLoc!");
3566
3567 const StackFrame *SF = Pred->getStackFrame();
3568 PostStmt DefaultPP(StoreE, SF);
3569
3570 if (!PP)
3571 PP = &DefaultPP;
3572
3573 // Do a previsit of the bind.
3574 ExplodedNodeSet CheckedSet;
3575 getCheckerManager().runCheckersForBind(Dst&: CheckedSet, Src: Pred, location: Location, val: Val,
3576 S: StoreE, AtDeclInit, Eng&: *this, PP: *PP);
3577
3578 for (ExplodedNode *PredI : CheckedSet) {
3579 ProgramStateRef State = PredI->getState();
3580
3581 // Check and record that 'Val' may escape:
3582 State = processPointerEscapedOnBind(State, Loc: Location, Val, SF);
3583
3584 if (auto AsLoc = Location.getAs<Loc>()) {
3585 // When binding the value, pass on the hint that this is a
3586 // initialization. For initializations, we do not need to inform clients
3587 // of region changes.
3588 State = State->bindLoc(location: *AsLoc, V: Val, SF, /*notifyChanges=*/!AtDeclInit);
3589 }
3590
3591 PostStore PS(StoreE, SF, Location.getAsRegion(), /*tag=*/nullptr);
3592 Dst.insert(N: Engine.makeNode(Loc: PS, State, Pred: PredI));
3593 }
3594}
3595
3596/// evalStore - Handle the semantics of a store via an assignment.
3597/// @param Dst The node set to store generated state nodes
3598/// @param AssignE The assignment expression if the store happens in an
3599/// assignment.
3600/// @param LocationE The location expression that is stored to.
3601/// @param state The current simulation state
3602/// @param location The location to store the value
3603/// @param Val The value to be stored
3604void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
3605 const Expr *LocationE,
3606 ExplodedNode *Pred,
3607 ProgramStateRef state, SVal location, SVal Val,
3608 const ProgramPointTag *tag) {
3609 // Proceed with the store. We use AssignE as the anchor for the PostStore
3610 // ProgramPoint if it is non-NULL, and LocationE otherwise.
3611 const Expr *StoreE = AssignE ? AssignE : LocationE;
3612
3613 // Evaluate the location (checks for bad dereferences).
3614 ExplodedNodeSet Tmp;
3615 evalLocation(Dst&: Tmp, NodeEx: AssignE, BoundEx: LocationE, Pred, St: state, location, isLoad: false);
3616
3617 if (Tmp.empty())
3618 return;
3619
3620 if (location.isUndef())
3621 return;
3622
3623 for (const auto I : Tmp)
3624 evalBind(Dst, StoreE, Pred: I, Location: location, Val, AtDeclInit: false);
3625}
3626
3627void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
3628 const Expr *NodeEx,
3629 const Expr *BoundEx,
3630 ExplodedNode *Pred,
3631 ProgramStateRef state,
3632 SVal location,
3633 const ProgramPointTag *tag,
3634 QualType LoadTy) {
3635 assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
3636 assert(NodeEx);
3637 assert(BoundEx);
3638 // Evaluate the location (checks for bad dereferences).
3639 ExplodedNodeSet Tmp;
3640 evalLocation(Dst&: Tmp, NodeEx, BoundEx, Pred, St: state, location, isLoad: true);
3641 if (Tmp.empty())
3642 return;
3643
3644 NodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
3645 if (location.isUndef())
3646 return;
3647
3648 // Proceed with the load.
3649 for (const auto I : Tmp) {
3650 state = I->getState();
3651
3652 SVal V = UnknownVal();
3653 if (location.isValid()) {
3654 if (LoadTy.isNull())
3655 LoadTy = BoundEx->getType();
3656 V = state->getSVal(LV: location.castAs<Loc>(), T: LoadTy);
3657 }
3658
3659 Bldr.generateNode(S: NodeEx, Pred: I,
3660 St: state->BindExpr(E: BoundEx, SF: I->getStackFrame(), V), tag,
3661 K: ProgramPoint::PostLoadKind);
3662 }
3663}
3664
3665void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
3666 const Stmt *NodeEx,
3667 const Stmt *BoundEx,
3668 ExplodedNode *Pred,
3669 ProgramStateRef state,
3670 SVal location,
3671 bool isLoad) {
3672 NodeBuilder BldrTop(Pred, Dst, *currBldrCtx);
3673 // Early checks for performance reason.
3674 if (location.isUnknown()) {
3675 return;
3676 }
3677
3678 ExplodedNodeSet Src;
3679 BldrTop.takeNodes(N: Pred);
3680 NodeBuilder Bldr(Pred, Src, *currBldrCtx);
3681 if (Pred->getState() != state) {
3682 // Associate this new state with an ExplodedNode.
3683 // FIXME: If I pass null tag, the graph is incorrect, e.g for
3684 // int *p;
3685 // p = 0;
3686 // *p = 0xDEADBEEF;
3687 // "p = 0" is not noted as "Null pointer value stored to 'p'" but
3688 // instead "int *p" is noted as
3689 // "Variable 'p' initialized to a null pointer value"
3690
3691 static SimpleProgramPointTag tag(TagProviderName, "Location");
3692 Bldr.generateNode(S: NodeEx, Pred, St: state, tag: &tag);
3693 }
3694 ExplodedNodeSet Tmp;
3695 getCheckerManager().runCheckersForLocation(Dst&: Tmp, Src, location, isLoad,
3696 NodeEx, BoundEx, Eng&: *this);
3697 BldrTop.addNodes(S: Tmp);
3698}
3699
3700std::pair<const ProgramPointTag *, const ProgramPointTag *>
3701ExprEngine::getEagerlyAssumeBifurcationTags() {
3702 static SimpleProgramPointTag TrueTag(TagProviderName, "Eagerly Assume True"),
3703 FalseTag(TagProviderName, "Eagerly Assume False");
3704
3705 return std::make_pair(x: &TrueTag, y: &FalseTag);
3706}
3707
3708/// If the last EagerlyAssume attempt was successful (i.e. the true and false
3709/// cases were both feasible), this state trait stores the expression where it
3710/// happened; otherwise this holds nullptr.
3711REGISTER_TRAIT_WITH_PROGRAMSTATE(LastEagerlyAssumeExprIfSuccessful,
3712 const Expr *)
3713
3714void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst,
3715 ExplodedNodeSet &Src,
3716 const Expr *Ex) {
3717 for (ExplodedNode *Pred : Src) {
3718 const StackFrame *SF = Pred->getStackFrame();
3719 // Test if the previous node was as the same expression. This can happen
3720 // when the expression fails to evaluate to anything meaningful and
3721 // (as an optimization) we don't generate a node.
3722 ProgramPoint P = Pred->getLocation();
3723 if (!P.getAs<PostStmt>() || P.castAs<PostStmt>().getStmt() != Ex) {
3724 Dst.insert(N: Pred);
3725 continue;
3726 }
3727
3728 ProgramStateRef State = Pred->getState();
3729 State = State->set<LastEagerlyAssumeExprIfSuccessful>(nullptr);
3730 SVal V = State->getSVal(E: Ex, SF);
3731 std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
3732 if (SEV && SEV->isExpression()) {
3733 const auto &[TrueTag, FalseTag] = getEagerlyAssumeBifurcationTags();
3734
3735 auto [StateTrue, StateFalse] = State->assume(Cond: *SEV);
3736
3737 if (StateTrue && StateFalse) {
3738 StateTrue = StateTrue->set<LastEagerlyAssumeExprIfSuccessful>(Ex);
3739 StateFalse = StateFalse->set<LastEagerlyAssumeExprIfSuccessful>(Ex);
3740 }
3741
3742 // First assume that the condition is true.
3743 if (StateTrue) {
3744 SVal Val = svalBuilder.makeIntVal(integer: 1U, type: Ex->getType());
3745 StateTrue = StateTrue->BindExpr(E: Ex, SF, V: Val);
3746 PostStmt PostStmtTrue(Ex, SF, TrueTag);
3747 Dst.insert(N: Engine.makeNode(Loc: PostStmtTrue, State: StateTrue, Pred));
3748 }
3749
3750 // Next, assume that the condition is false.
3751 if (StateFalse) {
3752 SVal Val = svalBuilder.makeIntVal(integer: 0U, type: Ex->getType());
3753 StateFalse = StateFalse->BindExpr(E: Ex, SF, V: Val);
3754 PostStmt PostStmtFalse(Ex, SF, FalseTag);
3755 Dst.insert(N: Engine.makeNode(Loc: PostStmtFalse, State: StateFalse, Pred));
3756 }
3757 } else {
3758 Dst.insert(N: Pred);
3759 }
3760 }
3761}
3762
3763bool ExprEngine::didEagerlyAssumeBifurcateAt(ProgramStateRef State,
3764 const Expr *Ex) const {
3765 return Ex && State->get<LastEagerlyAssumeExprIfSuccessful>() == Ex;
3766}
3767
3768void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
3769 ExplodedNodeSet &Dst) {
3770 // We have processed both the inputs and the outputs. All of the outputs
3771 // should evaluate to Locs. Nuke all of their values.
3772
3773 // FIXME: Some day in the future it would be nice to allow a "plug-in"
3774 // which interprets the inline asm and stores proper results in the
3775 // outputs.
3776
3777 ProgramStateRef state = Pred->getState();
3778
3779 for (const Expr *O : A->outputs()) {
3780 SVal X = state->getSVal(E: O, SF: Pred->getStackFrame());
3781 assert(!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
3782
3783 if (std::optional<Loc> LV = X.getAs<Loc>())
3784 state = state->invalidateRegions(Values: *LV, Elem: getCFGElementRef(),
3785 BlockCount: getNumVisitedCurrent(),
3786 SF: Pred->getStackFrame(),
3787 /*CausedByPointerEscape=*/CausesPointerEscape: true);
3788 }
3789
3790 // Do not reason about locations passed inside inline assembly.
3791 for (const Expr *I : A->inputs()) {
3792 SVal X = state->getSVal(E: I, SF: Pred->getStackFrame());
3793
3794 if (std::optional<Loc> LV = X.getAs<Loc>())
3795 state = state->invalidateRegions(Values: *LV, Elem: getCFGElementRef(),
3796 BlockCount: getNumVisitedCurrent(),
3797 SF: Pred->getStackFrame(),
3798 /*CausedByPointerEscape=*/CausesPointerEscape: true);
3799 }
3800
3801 Dst.insert(N: Engine.makePostStmtNode(S: A, State: state, Pred));
3802}
3803
3804void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
3805 ExplodedNodeSet &Dst) {
3806 Dst.insert(N: Engine.makePostStmtNode(S: A, State: Pred->getState(), Pred));
3807}
3808
3809//===----------------------------------------------------------------------===//
3810// Visualization.
3811//===----------------------------------------------------------------------===//
3812
3813namespace llvm {
3814
3815template<>
3816struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
3817 DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
3818
3819 static bool nodeHasBugReport(const ExplodedNode *N) {
3820 BugReporter &BR = static_cast<ExprEngine &>(
3821 N->getState()->getStateManager().getOwningEngine()).getBugReporter();
3822
3823 for (const auto &Class : BR.equivalenceClasses()) {
3824 for (const auto &Report : Class.getReports()) {
3825 const auto *PR = dyn_cast<PathSensitiveBugReport>(Val: Report.get());
3826 if (!PR)
3827 continue;
3828 const ExplodedNode *EN = PR->getErrorNode();
3829 if (EN->getState() == N->getState() &&
3830 EN->getLocation() == N->getLocation())
3831 return true;
3832 }
3833 }
3834 return false;
3835 }
3836
3837 /// \p PreCallback: callback before break.
3838 /// \p PostCallback: callback after break.
3839 /// \p Stop: stop iteration if returns @c true
3840 /// \return Whether @c Stop ever returned @c true.
3841 static bool traverseHiddenNodes(
3842 const ExplodedNode *N,
3843 llvm::function_ref<void(const ExplodedNode *)> PreCallback,
3844 llvm::function_ref<void(const ExplodedNode *)> PostCallback,
3845 llvm::function_ref<bool(const ExplodedNode *)> Stop) {
3846 while (true) {
3847 PreCallback(N);
3848 if (Stop(N))
3849 return true;
3850
3851 if (N->succ_size() != 1 || !isNodeHidden(N: N->getFirstSucc(), G: nullptr))
3852 break;
3853 PostCallback(N);
3854
3855 N = N->getFirstSucc();
3856 }
3857 return false;
3858 }
3859
3860 static bool isNodeHidden(const ExplodedNode *N, const ExplodedGraph *G) {
3861 return N->isTrivial();
3862 }
3863
3864 static std::string getNodeLabel(const ExplodedNode *N, ExplodedGraph *G){
3865 std::string Buf;
3866 llvm::raw_string_ostream Out(Buf);
3867
3868 const bool IsDot = true;
3869 const unsigned int Space = 1;
3870 ProgramStateRef State = N->getState();
3871
3872 Out << "{ \"state_id\": " << State->getID()
3873 << ",\\l";
3874
3875 Indent(Out, Space, IsDot) << "\"program_points\": [\\l";
3876
3877 // Dump program point for all the previously skipped nodes.
3878 traverseHiddenNodes(
3879 N,
3880 PreCallback: [&](const ExplodedNode *OtherNode) {
3881 Indent(Out, Space: Space + 1, IsDot) << "{ ";
3882 OtherNode->getLocation().printJson(Out, /*NL=*/"\\l");
3883 Out << ", \"tag\": ";
3884 if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag())
3885 Out << '\"' << Tag->getDebugTag() << '\"';
3886 else
3887 Out << "null";
3888 Out << ", \"node_id\": " << OtherNode->getID() <<
3889 ", \"is_sink\": " << OtherNode->isSink() <<
3890 ", \"has_report\": " << nodeHasBugReport(N: OtherNode) << " }";
3891 },
3892 // Adds a comma and a new-line between each program point.
3893 PostCallback: [&](const ExplodedNode *) { Out << ",\\l"; },
3894 Stop: [&](const ExplodedNode *) { return false; });
3895
3896 Out << "\\l"; // Adds a new-line to the last program point.
3897 Indent(Out, Space, IsDot) << "],\\l";
3898
3899 State->printDOT(Out, SF: N->getStackFrame(), Space);
3900
3901 Out << "\\l}\\l";
3902 return Buf;
3903 }
3904};
3905
3906} // namespace llvm
3907
3908void ExprEngine::ViewGraph(bool trim) {
3909 std::string Filename = DumpGraph(trim);
3910 llvm::DisplayGraph(Filename, wait: false, program: llvm::GraphProgram::DOT);
3911}
3912
3913void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode *> Nodes) {
3914 std::string Filename = DumpGraph(Nodes);
3915 llvm::DisplayGraph(Filename, wait: false, program: llvm::GraphProgram::DOT);
3916}
3917
3918std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) {
3919 if (trim) {
3920 std::vector<const ExplodedNode *> Src;
3921
3922 // Iterate through the reports and get their nodes.
3923 for (const auto &Class : BR.equivalenceClasses()) {
3924 const auto *R =
3925 dyn_cast<PathSensitiveBugReport>(Val: Class.getReports()[0].get());
3926 if (!R)
3927 continue;
3928 const auto *N = const_cast<ExplodedNode *>(R->getErrorNode());
3929 Src.push_back(x: N);
3930 }
3931 return DumpGraph(Nodes: Src, Filename);
3932 }
3933
3934 // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
3935 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
3936 return llvm::WriteGraph(G: &G, Name: "ExprEngine", /*ShortNames=*/false,
3937 /*Title=*/"Exploded Graph",
3938 /*Filename=*/std::string(Filename));
3939}
3940
3941std::string ExprEngine::DumpGraph(ArrayRef<const ExplodedNode *> Nodes,
3942 StringRef Filename) {
3943 std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes));
3944
3945 if (!TrimmedG) {
3946 llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
3947 return "";
3948 }
3949
3950 // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
3951 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
3952 return llvm::WriteGraph(G: TrimmedG.get(), Name: "TrimmedExprEngine",
3953 /*ShortNames=*/false,
3954 /*Title=*/"Trimmed Exploded Graph",
3955 /*Filename=*/std::string(Filename));
3956}
3957
3958void *ProgramStateTrait<ReplayWithoutInlining>::GDMIndex() {
3959 static int index = 0;
3960 return &index;
3961}
3962
3963void ExprEngine::anchor() { }
3964
3965void ExprEngine::ConstructInitList(const Expr *E, ArrayRef<Expr *> Args,
3966 bool IsTransparent, ExplodedNode *Pred,
3967 ExplodedNodeSet &Dst) {
3968 assert((isa<InitListExpr, CXXParenListInitExpr>(E)));
3969
3970 const StackFrame *SF = Pred->getStackFrame();
3971
3972 ProgramStateRef S = Pred->getState();
3973 QualType T = E->getType().getCanonicalType();
3974
3975 bool IsCompound = T->isArrayType() || T->isRecordType() ||
3976 T->isAnyComplexType() || T->isVectorType();
3977
3978 SVal Val;
3979 if (Args.size() > 1 || (E->isPRValue() && IsCompound && !IsTransparent)) {
3980 llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
3981 for (Expr *E : llvm::reverse(C&: Args))
3982 ArgList = getBasicVals().prependSVal(X: S->getSVal(E, SF), L: ArgList);
3983
3984 Val = getSValBuilder().makeCompoundVal(type: T, vals: ArgList);
3985 } else if (Args.size() == 0) {
3986 Val = getSValBuilder().makeZeroVal(type: T);
3987 } else {
3988 Val = S->getSVal(E: Args.front(), SF);
3989 }
3990 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E, V: Val));
3991}
3992