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 if (ExplodedNode *N = Engine.makeNode(Loc: PP, State: NewState, Pred))
1142 Engine.enqueueStmtNode(N, Block: getCurrBlock(), Idx: currStmtIdx);
1143}
1144
1145void ExprEngine::ProcessLifetimeEnd(const Stmt *S, const VarDecl *D,
1146 ExplodedNode *Pred) {
1147 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1148 S->getBeginLoc(),
1149 "Error evaluating end of a lifetime");
1150 LifetimeEnd PP(S, D, Pred->getStackFrame());
1151 ExplodedNode *Src = Engine.makeNode(Loc: PP, State: Pred->getState(), Pred);
1152
1153 ExplodedNodeSet Dst;
1154 getCheckerManager().runCheckersForLifetimeEnd(Dst, Src, Decl: D, Eng&: *this);
1155 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1156}
1157
1158void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
1159 ExplodedNode *Pred) {
1160 const CXXCtorInitializer *BMI = CFGInit.getInitializer();
1161 const Expr *Init = BMI->getInit()->IgnoreImplicit();
1162 const StackFrame *SF = Pred->getStackFrame();
1163
1164 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1165 BMI->getSourceLocation(),
1166 "Error evaluating initializer");
1167
1168 // We don't clean up dead bindings here.
1169 const auto *decl = cast<CXXConstructorDecl>(Val: SF->getDecl());
1170
1171 ProgramStateRef State = Pred->getState();
1172 SVal thisVal = State->getSVal(LV: svalBuilder.getCXXThis(D: decl, SF));
1173
1174 ExplodedNodeSet Tmp;
1175 SVal FieldLoc;
1176
1177 // Evaluate the initializer, if necessary
1178 if (BMI->isAnyMemberInitializer()) {
1179 // Constructors build the object directly in the field,
1180 // but non-objects must be copied in from the initializer.
1181 if (getObjectUnderConstruction(State, Item: BMI, SF)) {
1182 // The field was directly constructed, so there is no need to bind.
1183 // But we still need to stop tracking the object under construction.
1184 State = finishObjectConstruction(State, Item: BMI, SF);
1185 PostStore PS(Init, SF, /*Loc*/ nullptr, /*tag*/ nullptr);
1186 Tmp.insert(N: Engine.makeNode(Loc: PS, State, Pred));
1187 } else {
1188 const ValueDecl *Field;
1189 if (BMI->isIndirectMemberInitializer()) {
1190 Field = BMI->getIndirectMember();
1191 FieldLoc = State->getLValue(decl: BMI->getIndirectMember(), Base: thisVal);
1192 } else {
1193 Field = BMI->getMember();
1194 FieldLoc = State->getLValue(decl: BMI->getMember(), Base: thisVal);
1195 }
1196
1197 SVal InitVal;
1198 if (Field->getType()->isArrayType()) {
1199 // Handle arrays of trivial type. We can represent this with a
1200 // primitive load/copy from the base array region.
1201 const ArraySubscriptExpr *ASE;
1202 while ((ASE = dyn_cast<ArraySubscriptExpr>(Val: Init)))
1203 Init = ASE->getBase()->IgnoreImplicit();
1204
1205 InitVal = State->getSVal(E: Init, SF);
1206
1207 // If we fail to get the value for some reason, use a symbolic value.
1208 if (InitVal.isUnknownOrUndef()) {
1209 SValBuilder &SVB = getSValBuilder();
1210 InitVal = SVB.conjureSymbolVal(
1211 elem: getCFGElementRef(), SF, type: Field->getType(), visitCount: getNumVisitedCurrent());
1212 }
1213 } else {
1214 InitVal = State->getSVal(E: BMI->getInit(), SF);
1215 }
1216
1217 PostInitializer PP(BMI, FieldLoc.getAsRegion(), SF);
1218 evalBind(Dst&: Tmp, StoreE: Init, Pred, location: FieldLoc, Val: InitVal, /*isInit=*/AtDeclInit: true, PP: &PP);
1219 }
1220 } else if (BMI->isBaseInitializer() && isa<InitListExpr>(Val: Init)) {
1221 // When the base class is initialized with an initialization list and the
1222 // base class does not have a ctor, there will not be a CXXConstructExpr to
1223 // initialize the base region. Hence, we need to make the bind for it.
1224 SVal BaseLoc = getStoreManager().evalDerivedToBase(
1225 Derived: thisVal, DerivedPtrType: QualType(BMI->getBaseClass(), 0), IsVirtual: BMI->isBaseVirtual());
1226 SVal InitVal = State->getSVal(E: Init, SF);
1227 evalBind(Dst&: Tmp, StoreE: Init, Pred, location: BaseLoc, Val: InitVal, /*isInit=*/AtDeclInit: true);
1228 } else {
1229 assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
1230 Tmp.insert(N: Pred);
1231 // We already did all the work when visiting the CXXConstructExpr.
1232 }
1233
1234 // Construct PostInitializer nodes whether the state changed or not,
1235 // so that the diagnostics don't get confused.
1236 PostInitializer PP(BMI, FieldLoc.getAsRegion(), SF);
1237
1238 ExplodedNodeSet Dst;
1239 for (ExplodedNode *Pred : Tmp)
1240 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1241 // Enqueue the new nodes onto the work list.
1242 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1243}
1244
1245std::pair<ProgramStateRef, uint64_t>
1246ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State,
1247 const MemRegion *Region,
1248 const QualType &ElementTy,
1249 const StackFrame *SF,
1250 SVal *ElementCountVal) {
1251 assert(Region != nullptr && "Not-null region expected");
1252
1253 QualType Ty = ElementTy.getDesugaredType(Context: getContext());
1254 while (const auto *NTy = dyn_cast<ArrayType>(Val&: Ty))
1255 Ty = NTy->getElementType().getDesugaredType(Context: getContext());
1256
1257 auto ElementCount = getDynamicElementCount(State, MR: Region, SVB&: svalBuilder, Ty);
1258
1259 if (ElementCountVal)
1260 *ElementCountVal = ElementCount;
1261
1262 // Note: the destructors are called in reverse order.
1263 unsigned Idx = 0;
1264 if (auto OptionalIdx = getPendingArrayDestruction(State, SF)) {
1265 Idx = *OptionalIdx;
1266 } else {
1267 // The element count is either unknown, or an SVal that's not an integer.
1268 if (!ElementCount.isConstant())
1269 return {State, 0};
1270
1271 Idx = ElementCount.getAsInteger()->getLimitedValue();
1272 }
1273
1274 if (Idx == 0)
1275 return {State, 0};
1276
1277 --Idx;
1278
1279 return {setPendingArrayDestruction(State, SF, Idx), Idx};
1280}
1281
1282void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
1283 ExplodedNode *Pred) {
1284 ExplodedNodeSet Dst;
1285 switch (D.getKind()) {
1286 case CFGElement::AutomaticObjectDtor:
1287 ProcessAutomaticObjDtor(D: D.castAs<CFGAutomaticObjDtor>(), Pred, Dst);
1288 break;
1289 case CFGElement::BaseDtor:
1290 ProcessBaseDtor(D: D.castAs<CFGBaseDtor>(), Pred, Dst);
1291 break;
1292 case CFGElement::MemberDtor:
1293 ProcessMemberDtor(D: D.castAs<CFGMemberDtor>(), Pred, Dst);
1294 break;
1295 case CFGElement::TemporaryDtor:
1296 ProcessTemporaryDtor(D: D.castAs<CFGTemporaryDtor>(), Pred, Dst);
1297 break;
1298 case CFGElement::DeleteDtor:
1299 ProcessDeleteDtor(D: D.castAs<CFGDeleteDtor>(), Pred, Dst);
1300 break;
1301 default:
1302 llvm_unreachable("Unexpected dtor kind.");
1303 }
1304
1305 // Enqueue the new nodes onto the work list.
1306 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1307}
1308
1309void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
1310 ExplodedNode *Pred) {
1311 ExplodedNodeSet Dst;
1312 AnalysisManager &AMgr = getAnalysisManager();
1313 AnalyzerOptions &Opts = AMgr.options;
1314 // TODO: We're not evaluating allocators for all cases just yet as
1315 // we're not handling the return value correctly, which causes false
1316 // positives when the alpha.cplusplus.NewDeleteLeaks check is on.
1317 if (Opts.MayInlineCXXAllocator)
1318 VisitCXXNewAllocatorCall(CNE: NE, Pred, Dst);
1319 else {
1320 const StackFrame *SF = Pred->getStackFrame();
1321 PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), SF,
1322 getCFGElementRef());
1323 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1324 }
1325 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1326}
1327
1328void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
1329 ExplodedNode *Pred,
1330 ExplodedNodeSet &Dst) {
1331 const auto *DtorDecl = Dtor.getDestructorDecl(astContext&: getContext());
1332 const VarDecl *varDecl = Dtor.getVarDecl();
1333 QualType varType = varDecl->getType();
1334
1335 ProgramStateRef state = Pred->getState();
1336 const StackFrame *SF = Pred->getStackFrame();
1337
1338 SVal dest = state->getLValue(VD: varDecl, SF);
1339 const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion();
1340
1341 if (varType->isReferenceType()) {
1342 const MemRegion *ValueRegion = state->getSVal(R: Region).getAsRegion();
1343 if (!ValueRegion) {
1344 // FIXME: This should not happen. The language guarantees a presence
1345 // of a valid initializer here, so the reference shall not be undefined.
1346 // It seems that we're calling destructors over variables that
1347 // were not initialized yet.
1348 return;
1349 }
1350 Region = ValueRegion->getBaseRegion();
1351 varType = cast<TypedValueRegion>(Val: Region)->getValueType();
1352 }
1353
1354 unsigned Idx = 0;
1355 if (isa<ArrayType>(Val: varType)) {
1356 SVal ElementCount;
1357 std::tie(args&: state, args&: Idx) = prepareStateForArrayDestruction(
1358 State: state, Region, ElementTy: varType, SF, ElementCountVal: &ElementCount);
1359
1360 if (ElementCount.isConstant()) {
1361 uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
1362 assert(ArrayLength &&
1363 "An automatic dtor for a 0 length array shouldn't be triggered!");
1364
1365 // Still handle this case if we don't have assertions enabled.
1366 if (!ArrayLength) {
1367 static SimpleProgramPointTag PT(
1368 "ExprEngine", "Skipping automatic 0 length array destruction, "
1369 "which shouldn't be in the CFG.");
1370 PostImplicitCall PP(DtorDecl, varDecl->getLocation(), SF,
1371 getCFGElementRef(), &PT);
1372 Engine.makeNode(Loc: PP, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
1373 return;
1374 }
1375 }
1376 }
1377
1378 EvalCallOptions CallOpts;
1379 Region = makeElementRegion(State: state, LValue: loc::MemRegionVal(Region), Ty&: varType,
1380 IsArray&: CallOpts.IsArrayCtorOrDtor, Idx)
1381 .getAsRegion();
1382
1383 static SimpleProgramPointTag PT("ExprEngine",
1384 "Prepare for object destruction");
1385 PreImplicitCall PP(DtorDecl, varDecl->getLocation(), SF, getCFGElementRef(),
1386 &PT);
1387 Pred = Engine.makeNode(Loc: PP, State: state, Pred);
1388
1389 if (!Pred)
1390 return;
1391
1392 VisitCXXDestructor(ObjectType: varType, Dest: Region, S: Dtor.getTriggerStmt(),
1393 /*IsBase=*/IsBaseDtor: false, Pred, Dst, Options&: CallOpts);
1394}
1395
1396void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
1397 ExplodedNode *Pred,
1398 ExplodedNodeSet &Dst) {
1399 ProgramStateRef State = Pred->getState();
1400 const StackFrame *SF = Pred->getStackFrame();
1401 const CXXDeleteExpr *DE = Dtor.getDeleteExpr();
1402 const Expr *Arg = DE->getArgument();
1403 QualType DTy = DE->getDestroyedType();
1404 SVal ArgVal = State->getSVal(E: Arg, SF);
1405
1406 // If the argument to delete is known to be a null value,
1407 // don't run destructor.
1408 if (State->isNull(V: ArgVal).isConstrainedTrue()) {
1409 QualType BTy = getContext().getBaseElementType(QT: DTy);
1410 const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl();
1411 const CXXDestructorDecl *Dtor = RD->getDestructor();
1412
1413 PostImplicitCall PP(Dtor, DE->getBeginLoc(), SF, getCFGElementRef());
1414 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1415 return;
1416 }
1417
1418 auto getDtorDecl = [](const QualType &DTy) {
1419 const CXXRecordDecl *RD = DTy->getAsCXXRecordDecl();
1420 return RD->getDestructor();
1421 };
1422
1423 unsigned Idx = 0;
1424 EvalCallOptions CallOpts;
1425 const MemRegion *ArgR = ArgVal.getAsRegion();
1426
1427 if (DE->isArrayForm()) {
1428 CallOpts.IsArrayCtorOrDtor = true;
1429 // Yes, it may even be a multi-dimensional array.
1430 while (const auto *AT = getContext().getAsArrayType(T: DTy))
1431 DTy = AT->getElementType();
1432
1433 if (ArgR) {
1434 SVal ElementCount;
1435 std::tie(args&: State, args&: Idx) =
1436 prepareStateForArrayDestruction(State, Region: ArgR, ElementTy: DTy, SF, ElementCountVal: &ElementCount);
1437
1438 // If we're about to destruct a 0 length array, don't run any of the
1439 // destructors.
1440 if (ElementCount.isConstant() &&
1441 ElementCount.getAsInteger()->getLimitedValue() == 0) {
1442
1443 static SimpleProgramPointTag PT(
1444 "ExprEngine", "Skipping 0 length array delete destruction");
1445 PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), SF,
1446 getCFGElementRef(), &PT);
1447 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1448 return;
1449 }
1450
1451 ArgR = State->getLValue(ElementType: DTy, Idx: svalBuilder.makeArrayIndex(idx: Idx), Base: ArgVal)
1452 .getAsRegion();
1453 }
1454 }
1455
1456 static SimpleProgramPointTag PT("ExprEngine",
1457 "Prepare for object destruction");
1458 PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), SF,
1459 getCFGElementRef(), &PT);
1460 Pred = Engine.makeNode(Loc: PP, State, Pred);
1461
1462 if (!Pred)
1463 return;
1464
1465 VisitCXXDestructor(ObjectType: DTy, Dest: ArgR, S: DE, /*IsBase=*/IsBaseDtor: false, Pred, Dst, Options&: CallOpts);
1466}
1467
1468void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
1469 ExplodedNode *Pred, ExplodedNodeSet &Dst) {
1470 const StackFrame *SF = Pred->getStackFrame();
1471
1472 const auto *CurDtor = cast<CXXDestructorDecl>(Val: SF->getDecl());
1473 Loc ThisPtr = getSValBuilder().getCXXThis(D: CurDtor, SF);
1474 SVal ThisVal = Pred->getState()->getSVal(LV: ThisPtr);
1475
1476 // Create the base object region.
1477 const CXXBaseSpecifier *Base = D.getBaseSpecifier();
1478 QualType BaseTy = Base->getType();
1479 SVal BaseVal = getStoreManager().evalDerivedToBase(Derived: ThisVal, DerivedPtrType: BaseTy,
1480 IsVirtual: Base->isVirtual());
1481
1482 EvalCallOptions CallOpts;
1483 VisitCXXDestructor(ObjectType: BaseTy, Dest: BaseVal.getAsRegion(), S: CurDtor->getBody(),
1484 /*IsBase=*/IsBaseDtor: true, Pred, Dst, Options&: CallOpts);
1485}
1486
1487void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
1488 ExplodedNode *Pred, ExplodedNodeSet &Dst) {
1489 const auto *DtorDecl = D.getDestructorDecl(astContext&: getContext());
1490 const FieldDecl *Member = D.getFieldDecl();
1491 QualType T = Member->getType();
1492 ProgramStateRef State = Pred->getState();
1493 const StackFrame *SF = Pred->getStackFrame();
1494
1495 const auto *CurDtor = cast<CXXDestructorDecl>(Val: SF->getDecl());
1496 Loc ThisStorageLoc = getSValBuilder().getCXXThis(D: CurDtor, SF);
1497 Loc ThisLoc = State->getSVal(LV: ThisStorageLoc).castAs<Loc>();
1498 SVal FieldVal = State->getLValue(decl: Member, Base: ThisLoc);
1499
1500 unsigned Idx = 0;
1501 if (isa<ArrayType>(Val: T)) {
1502 SVal ElementCount;
1503 std::tie(args&: State, args&: Idx) = prepareStateForArrayDestruction(
1504 State, Region: FieldVal.getAsRegion(), ElementTy: T, SF, ElementCountVal: &ElementCount);
1505
1506 if (ElementCount.isConstant()) {
1507 uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
1508 assert(ArrayLength &&
1509 "A member dtor for a 0 length array shouldn't be triggered!");
1510
1511 // Still handle this case if we don't have assertions enabled.
1512 if (!ArrayLength) {
1513 static SimpleProgramPointTag PT(
1514 "ExprEngine", "Skipping member 0 length array destruction, which "
1515 "shouldn't be in the CFG.");
1516 PostImplicitCall PP(DtorDecl, Member->getLocation(), SF,
1517 getCFGElementRef(), &PT);
1518 Engine.makeNode(Loc: PP, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
1519 return;
1520 }
1521 }
1522 }
1523
1524 EvalCallOptions CallOpts;
1525 FieldVal =
1526 makeElementRegion(State, LValue: FieldVal, Ty&: T, IsArray&: CallOpts.IsArrayCtorOrDtor, Idx);
1527
1528 static SimpleProgramPointTag PT("ExprEngine",
1529 "Prepare for object destruction");
1530 PreImplicitCall PP(DtorDecl, Member->getLocation(), SF, getCFGElementRef(),
1531 &PT);
1532 Pred = Engine.makeNode(Loc: PP, State, Pred);
1533
1534 if (!Pred)
1535 return;
1536
1537 VisitCXXDestructor(ObjectType: T, Dest: FieldVal.getAsRegion(), S: CurDtor->getBody(),
1538 /*IsBase=*/IsBaseDtor: false, Pred, Dst, Options&: CallOpts);
1539}
1540
1541void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
1542 ExplodedNode *Pred,
1543 ExplodedNodeSet &Dst) {
1544 const CXXBindTemporaryExpr *BTE = D.getBindTemporaryExpr();
1545 ProgramStateRef State = Pred->getState();
1546 const StackFrame *SF = Pred->getStackFrame();
1547 const MemRegion *MR = nullptr;
1548
1549 if (std::optional<SVal> V = getObjectUnderConstruction(State, Item: BTE, SF)) {
1550 // FIXME: Currently we insert temporary destructors for default parameters,
1551 // but we don't insert the constructors, so the entry in
1552 // ObjectsUnderConstruction may be missing.
1553 State = finishObjectConstruction(State, Item: BTE, SF);
1554 MR = V->getAsRegion();
1555 }
1556
1557 // If copy elision has occurred, and the constructor corresponding to the
1558 // destructor was elided, we need to skip the destructor as well.
1559 if (isDestructorElided(State, BTE, SF)) {
1560 State = cleanupElidedDestructor(State, BTE, SF);
1561 PostImplicitCall PP(D.getDestructorDecl(astContext&: getContext()), BTE->getBeginLoc(),
1562 SF, getCFGElementRef());
1563 Dst.insert(N: Engine.makeNode(Loc: PP, State, Pred));
1564 return;
1565 }
1566
1567 ExplodedNode *CleanPred = Engine.makePostStmtNode(S: BTE, State, Pred);
1568 if (!CleanPred) {
1569 // FIXME: We can get a null node here due to temporaries being
1570 // bound to default parameters.
1571 CleanPred = Pred;
1572 }
1573
1574 QualType T = BTE->getSubExpr()->getType();
1575
1576 EvalCallOptions CallOpts;
1577 CallOpts.IsTemporaryCtorOrDtor = true;
1578 if (!MR) {
1579 // FIXME: If we have no MR, we still need to unwrap the array to avoid
1580 // destroying the whole array at once.
1581 //
1582 // For this case there is no universal solution as there is no way to
1583 // directly create an array of temporary objects. There are some expressions
1584 // however which can create temporary objects and have an array type.
1585 //
1586 // E.g.: std::initializer_list<S>{S(), S()};
1587 //
1588 // The expression above has a type of 'const struct S[2]' but it's a single
1589 // 'std::initializer_list<>'. The destructors of the 2 temporary 'S()'
1590 // objects will be called anyway, because they are 2 separate objects in 2
1591 // separate clusters, i.e.: not an array.
1592 //
1593 // Now the 'std::initializer_list<>' is not an array either even though it
1594 // has the type of an array. The point is, we only want to invoke the
1595 // destructor for the initializer list once not twice or so.
1596 while (const ArrayType *AT = getContext().getAsArrayType(T)) {
1597 T = AT->getElementType();
1598
1599 // FIXME: Enable this flag once we handle this case properly.
1600 // CallOpts.IsArrayCtorOrDtor = true;
1601 }
1602 } else {
1603 // FIXME: We'd eventually need to makeElementRegion() trick here,
1604 // but for now we don't have the respective construction contexts,
1605 // so MR would always be null in this case. Do nothing for now.
1606 }
1607 VisitCXXDestructor(ObjectType: T, Dest: MR, S: BTE,
1608 /*IsBase=*/IsBaseDtor: false, Pred: CleanPred, Dst, Options&: CallOpts);
1609}
1610
1611void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
1612 ExplodedNode *Pred,
1613 ExplodedNodeSet &Dst,
1614 const CFGBlock *DstT,
1615 const CFGBlock *DstF) {
1616 ProgramStateRef State = Pred->getState();
1617 const StackFrame *SF = Pred->getStackFrame();
1618
1619 std::optional<SVal> Obj = getObjectUnderConstruction(State, Item: BTE, SF);
1620 if (const CFGBlock *DstBlock = Obj ? DstT : DstF) {
1621 BlockEdge BE(getCurrBlock(), DstBlock, SF);
1622 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred));
1623 }
1624}
1625
1626void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
1627 ExplodedNodeSet &PreVisit,
1628 ExplodedNodeSet &Dst) {
1629 // This is a fallback solution in case we didn't have a construction
1630 // context when we were constructing the temporary. Otherwise the map should
1631 // have been populated there.
1632 if (!getAnalysisManager().options.ShouldIncludeTemporaryDtorsInCFG) {
1633 // In case we don't have temporary destructors in the CFG, do not mark
1634 // the initialization - we would otherwise never clean it up.
1635 Dst = PreVisit;
1636 return;
1637 }
1638 for (ExplodedNode *Node : PreVisit) {
1639 ProgramStateRef State = Node->getState();
1640 const StackFrame *SF = Node->getStackFrame();
1641 if (!getObjectUnderConstruction(State, Item: BTE, SF)) {
1642 // FIXME: Currently the state might also already contain the marker due to
1643 // incorrect handling of temporaries bound to default parameters; for
1644 // those, we currently skip the CXXBindTemporaryExpr but rely on adding
1645 // temporary destructor nodes.
1646 State = addObjectUnderConstruction(State, Item: BTE, SF, V: UnknownVal());
1647 }
1648 Dst.insert(N: Engine.makePostStmtNode(S: BTE, State, Pred: Node));
1649 }
1650}
1651
1652ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State,
1653 ArrayRef<SVal> Vs,
1654 PointerEscapeKind K,
1655 const CallEvent *Call) const {
1656 class CollectReachableSymbolsCallback final : public SymbolVisitor {
1657 InvalidatedSymbols &Symbols;
1658
1659 public:
1660 explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols)
1661 : Symbols(Symbols) {}
1662
1663 const InvalidatedSymbols &getSymbols() const { return Symbols; }
1664
1665 bool VisitSymbol(SymbolRef Sym) override {
1666 Symbols.insert(V: Sym);
1667 return true;
1668 }
1669 };
1670 InvalidatedSymbols Symbols;
1671 CollectReachableSymbolsCallback CallBack(Symbols);
1672 for (SVal V : Vs)
1673 State->scanReachableSymbols(val: V, visitor&: CallBack);
1674
1675 return getCheckerManager().runCheckersForPointerEscape(
1676 State, Escaped: CallBack.getSymbols(), Call, Kind: K, ITraits: nullptr);
1677}
1678
1679void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
1680 ExplodedNodeSet &Dst) {
1681 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1682 S->getBeginLoc(), "Error evaluating statement");
1683
1684 assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens());
1685
1686 switch (S->getStmtClass()) {
1687 // C++, OpenMP and ARC stuff we don't support yet.
1688 case Stmt::CXXDependentScopeMemberExprClass:
1689 case Stmt::CXXReflectExprClass:
1690 case Stmt::CXXTryStmtClass:
1691 case Stmt::CXXTypeidExprClass:
1692 case Stmt::CXXUuidofExprClass:
1693 case Stmt::CXXFoldExprClass:
1694 case Stmt::MSPropertyRefExprClass:
1695 case Stmt::MSPropertySubscriptExprClass:
1696 case Stmt::CXXUnresolvedConstructExprClass:
1697 case Stmt::DependentScopeDeclRefExprClass:
1698 case Stmt::ArrayTypeTraitExprClass:
1699 case Stmt::ExpressionTraitExprClass:
1700 case Stmt::UnresolvedLookupExprClass:
1701 case Stmt::UnresolvedMemberExprClass:
1702 case Stmt::DependentTemplateIdExprClass:
1703 case Stmt::RecoveryExprClass:
1704 case Stmt::CXXNoexceptExprClass:
1705 case Stmt::PackExpansionExprClass:
1706 case Stmt::PackIndexingExprClass:
1707 case Stmt::SubstNonTypeTemplateParmPackExprClass:
1708 case Stmt::FunctionParmPackExprClass:
1709 case Stmt::CoroutineBodyStmtClass:
1710 case Stmt::CoawaitExprClass:
1711 case Stmt::DependentCoawaitExprClass:
1712 case Stmt::CoreturnStmtClass:
1713 case Stmt::CoyieldExprClass:
1714 case Stmt::SEHTryStmtClass:
1715 case Stmt::SEHExceptStmtClass:
1716 case Stmt::SEHLeaveStmtClass:
1717 case Stmt::SEHFinallyStmtClass:
1718 case Stmt::CXXExpansionStmtPatternClass:
1719 case Stmt::CXXExpansionStmtInstantiationClass:
1720 case Stmt::CXXExpansionSelectExprClass:
1721 case Stmt::OMPCanonicalLoopClass:
1722 case Stmt::OMPParallelDirectiveClass:
1723 case Stmt::OMPSimdDirectiveClass:
1724 case Stmt::OMPForDirectiveClass:
1725 case Stmt::OMPForSimdDirectiveClass:
1726 case Stmt::OMPSectionsDirectiveClass:
1727 case Stmt::OMPSectionDirectiveClass:
1728 case Stmt::OMPScopeDirectiveClass:
1729 case Stmt::OMPSingleDirectiveClass:
1730 case Stmt::OMPMasterDirectiveClass:
1731 case Stmt::OMPCriticalDirectiveClass:
1732 case Stmt::OMPParallelForDirectiveClass:
1733 case Stmt::OMPParallelForSimdDirectiveClass:
1734 case Stmt::OMPParallelSectionsDirectiveClass:
1735 case Stmt::OMPParallelMasterDirectiveClass:
1736 case Stmt::OMPParallelMaskedDirectiveClass:
1737 case Stmt::OMPTaskDirectiveClass:
1738 case Stmt::OMPTaskyieldDirectiveClass:
1739 case Stmt::OMPBarrierDirectiveClass:
1740 case Stmt::OMPTaskwaitDirectiveClass:
1741 case Stmt::OMPErrorDirectiveClass:
1742 case Stmt::OMPTaskgroupDirectiveClass:
1743 case Stmt::OMPFlushDirectiveClass:
1744 case Stmt::OMPDepobjDirectiveClass:
1745 case Stmt::OMPScanDirectiveClass:
1746 case Stmt::OMPOrderedStandaloneDirectiveClass:
1747 case Stmt::OMPOrderedBlockAssocDirectiveClass:
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
2136 ExplodedNodeSet PostVisit;
2137 for (const auto i : PreVisit)
2138 VisitCXXDeleteExpr(CDE, Pred: i, Dst&: PostVisit);
2139
2140 getCheckerManager().runCheckersForPostStmt(Dst, Src: PostVisit, S, Eng&: *this);
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).
2393ExplodedNode *ExprEngine::processCFGBlockEntrance(const BlockEntrance &BE,
2394 ExplodedNode *Pred) {
2395 const StackFrame *SF = Pred->getStackFrame();
2396 const Stmt *Term = getCurrBlock()->getTerminatorStmt();
2397 ProgramStateRef State = Pred->getState();
2398 unsigned MaxBlockVisit = AMgr.options.maxBlockVisitOnPath;
2399
2400 // If we reach a loop which has a known bound (and meets other constraints)
2401 // then consider completely unrolling it.
2402 if (AMgr.options.ShouldUnrollLoops) {
2403 if (Term)
2404 State = updateLoopStack(LoopStmt: Term, ASTCtx&: AMgr.getASTContext(), Pred, maxVisitOnPath: MaxBlockVisit);
2405 // Is we are inside an unrolled loop then no need the check the counters.
2406 if (isUnrolledState(State))
2407 return Engine.makeNode(Loc: BE, State, Pred);
2408 }
2409
2410 // If this block is terminated by a loop and it has already been visited the
2411 // maximum number of times, widen the loop.
2412 unsigned int BlockCount = getNumVisitedCurrent();
2413 if (BlockCount == MaxBlockVisit - 1 && AMgr.options.ShouldWidenLoops) {
2414 if (!isa_and_nonnull<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(Val: Term))
2415 return Engine.makeNode(Loc: BE, State, Pred);
2416
2417 // FIXME:
2418 // We cannot use the CFG element from the via `ExprEngine::getCFGElementRef`
2419 // since we are currently at the block entrance and the current reference
2420 // would be stale. Ideally, we should pass on the terminator of the CFG
2421 // block, but the terminator cannot be referred as a CFG element.
2422 // Here we just pass the the first CFG element in the block.
2423 ProgramStateRef WidenedState = getWidenedLoopState(
2424 PrevState: State, SF, BlockCount, Elem: *getCurrBlock()->ref_begin());
2425 return Engine.makeNode(Loc: BE, State: WidenedState, Pred);
2426 }
2427
2428 // If we did not reach MaxBlockVisitOnPath, continue the analysis normally.
2429 if (BlockCount < MaxBlockVisit)
2430 return Engine.makeNode(Loc: BE, State, Pred);
2431
2432 // ... otherwise, discard this execution path.
2433 static SimpleProgramPointTag Tag(TagProviderName, "Block count exceeded");
2434 const ExplodedNode *Sink =
2435 Engine.makeNode(Loc: BE.withTag(tag: &Tag), State, Pred, /*MarkAsSink=*/true);
2436
2437 if (!SF->inTopFrame()) {
2438 // FIXME: This will unconditionally prevent inlining this function (even
2439 // from other entry points), which is not a reasonable heuristic: even if
2440 // we reached max block count on this particular execution path, there
2441 // may be other execution paths (especially with other parametrizations)
2442 // where the analyzer can reach the end of the function (so there is no
2443 // natural reason to avoid inlining it). However, disabling this would
2444 // significantly increase the analysis time (because more entry points
2445 // would exhaust their allocated budget), so it must be compensated by a
2446 // different (more reasonable) reduction of analysis scope.
2447 Engine.FunctionSummaries->markShouldNotInline(D: SF->getDecl());
2448
2449 // Re-run the call evaluation without inlining it, by storing the
2450 // no-inlining policy in the state and enqueuing the new work item on
2451 // the list. Replay should almost never fail. Use the stats to catch it
2452 // if it does.
2453 if (!AMgr.options.NoRetryExhausted && replayWithoutInlining(N: Pred, CalleeSF: SF))
2454 return nullptr;
2455 NumMaxBlockCountReachedInInlined++;
2456 } else
2457 NumMaxBlockCountReached++;
2458
2459 // Make sink nodes as exhausted(for stats) only if retry failed.
2460 Engine.blocksExhausted.push_back(x: std::make_pair(x: BE, y&: Sink));
2461
2462 return nullptr;
2463}
2464
2465void ExprEngine::runCheckersForBlockEntrance(const BlockEntrance &Entrance,
2466 ExplodedNode *Pred,
2467 ExplodedNodeSet &Dst) {
2468 llvm::PrettyStackTraceFormat CrashInfo(
2469 "Processing block entrance B%d -> B%d",
2470 Entrance.getPreviousBlock()->getBlockID(),
2471 Entrance.getBlock()->getBlockID());
2472 getCheckerManager().runCheckersForBlockEntrance(Dst, Src: Pred, Entrance, Eng&: *this);
2473}
2474
2475//===----------------------------------------------------------------------===//
2476// Branch processing.
2477//===----------------------------------------------------------------------===//
2478
2479/// RecoverCastedSymbol - A helper function for ProcessBranch that is used
2480/// to try to recover some path-sensitivity for casts of symbolic
2481/// integers that promote their values (which are currently not tracked well).
2482/// This function returns the SVal bound to Condition->IgnoreCasts if all the
2483// cast(s) did was sign-extend the original value.
2484static SVal RecoverCastedSymbol(ProgramStateRef state, const Stmt *Condition,
2485 const StackFrame *SF, ASTContext &Ctx) {
2486
2487 const auto *Ex = dyn_cast<Expr>(Val: Condition);
2488 if (!Ex)
2489 return UnknownVal();
2490
2491 uint64_t bits = 0;
2492 bool bitsInit = false;
2493
2494 while (const auto *CE = dyn_cast<CastExpr>(Val: Ex)) {
2495 QualType T = CE->getType();
2496
2497 if (!T->isIntegralOrEnumerationType())
2498 return UnknownVal();
2499
2500 uint64_t newBits = Ctx.getTypeSize(T);
2501 if (!bitsInit || newBits < bits) {
2502 bitsInit = true;
2503 bits = newBits;
2504 }
2505
2506 Ex = CE->getSubExpr();
2507 }
2508
2509 // We reached a non-cast. Is it a symbolic value?
2510 QualType T = Ex->getType();
2511
2512 if (!bitsInit || !T->isIntegralOrEnumerationType() ||
2513 Ctx.getTypeSize(T) > bits)
2514 return UnknownVal();
2515
2516 return state->getSVal(E: Ex, SF);
2517}
2518
2519#ifndef NDEBUG
2520static const Stmt *getRightmostLeaf(const Stmt *Condition) {
2521 while (Condition) {
2522 const auto *BO = dyn_cast<BinaryOperator>(Condition);
2523 if (!BO || !BO->isLogicalOp()) {
2524 return Condition;
2525 }
2526 Condition = BO->getRHS()->IgnoreParens();
2527 }
2528 return nullptr;
2529}
2530#endif
2531
2532// Returns the condition the branch at the end of 'B' depends on and whose value
2533// has been evaluated within 'B'.
2534// In most cases, the terminator condition of 'B' will be evaluated fully in
2535// the last statement of 'B'; in those cases, the resolved condition is the
2536// given 'Condition'.
2537// If the condition of the branch is a logical binary operator tree, the CFG is
2538// optimized: in that case, we know that the expression formed by all but the
2539// rightmost leaf of the logical binary operator tree must be true, and thus
2540// the branch condition is at this point equivalent to the truth value of that
2541// rightmost leaf; the CFG block thus only evaluates this rightmost leaf
2542// expression in its final statement. As the full condition in that case was
2543// not evaluated, and is thus not in the SVal cache, we need to use that leaf
2544// expression to evaluate the truth value of the condition in the current state
2545// space.
2546static const Stmt *ResolveCondition(const Stmt *Condition,
2547 const CFGBlock *B) {
2548 if (const auto *Ex = dyn_cast<Expr>(Val: Condition))
2549 Condition = Ex->IgnoreParens();
2550
2551 const auto *BO = dyn_cast<BinaryOperator>(Val: Condition);
2552 if (!BO || !BO->isLogicalOp())
2553 return Condition;
2554
2555 assert(B->getTerminator().isStmtBranch() &&
2556 "Other kinds of branches are handled separately!");
2557
2558 // For logical operations, we still have the case where some branches
2559 // use the traditional "merge" approach and others sink the branch
2560 // directly into the basic blocks representing the logical operation.
2561 // We need to distinguish between those two cases here.
2562
2563 // The invariants are still shifting, but it is possible that the
2564 // last element in a CFGBlock is not a CFGStmt. Look for the last
2565 // CFGStmt as the value of the condition.
2566 for (CFGElement Elem : llvm::reverse(C: *B)) {
2567 std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
2568 if (!CS)
2569 continue;
2570 const Stmt *LastStmt = CS->getStmt();
2571 assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition));
2572 return LastStmt;
2573 }
2574 llvm_unreachable("could not resolve condition");
2575}
2576
2577using ObjCForLctxPair =
2578 std::pair<const ObjCForCollectionStmt *, const StackFrame *>;
2579
2580REGISTER_MAP_WITH_PROGRAMSTATE(ObjCForHasMoreIterations, ObjCForLctxPair, bool)
2581
2582ProgramStateRef ExprEngine::setWhetherHasMoreIteration(
2583 ProgramStateRef State, const ObjCForCollectionStmt *O, const StackFrame *SF,
2584 bool HasMoreIteraton) {
2585 assert(!State->contains<ObjCForHasMoreIterations>({O, SF}));
2586 return State->set<ObjCForHasMoreIterations>(K: {O, SF}, E: HasMoreIteraton);
2587}
2588
2589ProgramStateRef ExprEngine::removeIterationState(ProgramStateRef State,
2590 const ObjCForCollectionStmt *O,
2591 const StackFrame *SF) {
2592 assert(State->contains<ObjCForHasMoreIterations>({O, SF}));
2593 return State->remove<ObjCForHasMoreIterations>(K: {O, SF});
2594}
2595
2596bool ExprEngine::hasMoreIteration(ProgramStateRef State,
2597 const ObjCForCollectionStmt *O,
2598 const StackFrame *SF) {
2599 assert(State->contains<ObjCForHasMoreIterations>({O, SF}));
2600 return *State->get<ObjCForHasMoreIterations>(key: {O, SF});
2601}
2602
2603/// Split the state on whether there are any more iterations left for this loop.
2604/// Returns a (HasMoreIteration, HasNoMoreIteration) pair, or std::nullopt when
2605/// the acquisition of the loop condition value failed.
2606static std::optional<std::pair<ProgramStateRef, ProgramStateRef>>
2607assumeCondition(const Stmt *ConditionStmt, ExplodedNode *N) {
2608 ProgramStateRef State = N->getState();
2609 if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(Val: ConditionStmt)) {
2610 bool HasMoreIteraton =
2611 ExprEngine::hasMoreIteration(State, O: ObjCFor, SF: N->getStackFrame());
2612 // Checkers have already ran on branch conditions, so the current
2613 // information as to whether the loop has more iteration becomes outdated
2614 // after this point.
2615 State =
2616 ExprEngine::removeIterationState(State, O: ObjCFor, SF: N->getStackFrame());
2617 if (HasMoreIteraton)
2618 return std::pair<ProgramStateRef, ProgramStateRef>{State, nullptr};
2619 else
2620 return std::pair<ProgramStateRef, ProgramStateRef>{nullptr, State};
2621 }
2622
2623 const auto *ConditionExpr = dyn_cast<Expr>(Val: ConditionStmt);
2624 assert(ConditionExpr && "The condition must be an Expr from here!");
2625
2626 SVal X = State->getSVal(E: ConditionExpr, SF: N->getStackFrame());
2627
2628 if (X.isUnknownOrUndef()) {
2629 // Give it a chance to recover from unknown.
2630 if (const auto *Ex = dyn_cast<Expr>(Val: ConditionExpr)) {
2631 if (Ex->getType()->isIntegralOrEnumerationType()) {
2632 // Try to recover some path-sensitivity. Right now casts of symbolic
2633 // integers that promote their values are currently not tracked well.
2634 // If 'ConditionExpr' is such an expression, try and recover the
2635 // underlying value and use that instead.
2636 SVal recovered =
2637 RecoverCastedSymbol(state: State, Condition: ConditionExpr, SF: N->getStackFrame(),
2638 Ctx&: N->getState()->getStateManager().getContext());
2639
2640 if (!recovered.isUnknown()) {
2641 X = recovered;
2642 }
2643 }
2644 }
2645 }
2646
2647 // If the condition is still unknown, give up.
2648 if (X.isUnknownOrUndef())
2649 return std::nullopt;
2650
2651 DefinedSVal V = X.castAs<DefinedSVal>();
2652
2653 return State->assume(Cond: V);
2654}
2655
2656void ExprEngine::processBranch(
2657 const Stmt *Condition, ExplodedNode *Pred, ExplodedNodeSet &Dst,
2658 const CFGBlock *DstT, const CFGBlock *DstF,
2659 std::optional<unsigned> IterationsCompletedInLoop) {
2660 assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) &&
2661 "CXXBindTemporaryExprs are handled by processBindTemporary.");
2662
2663 const StackFrame *SF = Pred->getStackFrame();
2664
2665 // Check for NULL conditions; e.g. "for(;;)"
2666 if (!Condition) {
2667 if (!DstT) {
2668 // I _hope_ that this "null condition + null transition to loop body"
2669 // case is impossible, but I cannot prove this, so let's cover it.
2670 return;
2671 }
2672 BlockEdge BE(getCurrBlock(), DstT, SF);
2673 Dst.insert(N: Engine.makeNode(Loc: BE, State: Pred->getState(), Pred));
2674 return;
2675 }
2676
2677 if (const auto *Ex = dyn_cast<Expr>(Val: Condition))
2678 Condition = Ex->IgnoreParens();
2679
2680 Condition = ResolveCondition(Condition, B: getCurrBlock());
2681 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
2682 Condition->getBeginLoc(),
2683 "Error evaluating branch");
2684
2685 ExplodedNodeSet CheckersOutSet;
2686 getCheckerManager().runCheckersForBranchCondition(condition: Condition, Dst&: CheckersOutSet,
2687 Pred, Eng&: *this);
2688 // We generated only sinks.
2689 if (CheckersOutSet.empty())
2690 return;
2691
2692 for (ExplodedNode *PredN : CheckersOutSet) {
2693 ProgramStateRef PrevState = PredN->getState();
2694
2695 ProgramStateRef StTrue = PrevState, StFalse = PrevState;
2696 if (const auto KnownCondValueAssumption = assumeCondition(ConditionStmt: Condition, N: PredN))
2697 std::tie(args&: StTrue, args&: StFalse) = *KnownCondValueAssumption;
2698
2699 if (StTrue && StFalse)
2700 assert(!isa<ObjCForCollectionStmt>(Condition));
2701
2702 // We want to ensure consistent behavior between `eagerly-assume=false`,
2703 // when the state split is always performed by the `assumeCondition()`
2704 // call within this function and `eagerly-assume=true` (the default), when
2705 // some conditions (comparison operators, unary negation) can trigger a
2706 // state split before this callback. There are some contrived corner cases
2707 // that behave differently with and without `eagerly-assume`, but I don't
2708 // know about an example that could plausibly appear in "real" code.
2709 bool BothFeasible =
2710 (StTrue && StFalse) ||
2711 didEagerlyAssumeBifurcateAt(State: PrevState, Ex: dyn_cast<Expr>(Val: Condition));
2712
2713 if (StTrue) {
2714 // In a loop, if both branches are feasible (i.e. the analyzer doesn't
2715 // understand the loop condition) and two iterations have already been
2716 // completed, then don't assume a third iteration because it is a
2717 // redundant execution path (unlikely to be different from earlier loop
2718 // exits) and can cause false positives if e.g. the loop iterates over a
2719 // two-element structure with an opaque condition.
2720 //
2721 // The iteration count "2" is hardcoded because it's the natural limit:
2722 // * the fact that the programmer wrote a loop (and not just an `if`)
2723 // implies that they thought that the loop body might be executed twice;
2724 // * however, there are situations where the programmer knows that there
2725 // are at most two iterations but writes a loop that appears to be
2726 // generic, because there is no special syntax for "loop with at most
2727 // two iterations". (This pattern is common in FFMPEG and appears in
2728 // many other projects as well.)
2729 bool CompletedTwoIterations = IterationsCompletedInLoop.value_or(u: 0) >= 2;
2730 bool SkipTrueBranch = BothFeasible && CompletedTwoIterations;
2731
2732 // FIXME: This "don't assume third iteration" heuristic partially
2733 // conflicts with the widen-loop analysis option (which is off by
2734 // default). If we intend to support and stabilize the loop widening,
2735 // we must ensure that it 'plays nicely' with this logic.
2736 if (!SkipTrueBranch || AMgr.options.ShouldWidenLoops) {
2737 if (DstT) {
2738 BlockEdge BE(getCurrBlock(), DstT, SF);
2739 Dst.insert(N: Engine.makeNode(Loc: BE, State: StTrue, Pred: PredN));
2740 }
2741 } else if (!AMgr.options.InlineFunctionsWithAmbiguousLoops) {
2742 // FIXME: There is an ancient and arbitrary heuristic in
2743 // `ExprEngine::processCFGBlockEntrance` which prevents all further
2744 // inlining of a function if it finds an execution path within that
2745 // function which reaches the `MaxBlockVisitOnPath` limit (a/k/a
2746 // `analyzer-max-loop`, by default four iterations in a loop). Adding
2747 // this "don't assume third iteration" logic significantly increased
2748 // the analysis runtime on some inputs because less functions were
2749 // arbitrarily excluded from being inlined, so more entry points used
2750 // up their full allocated budget. As a hacky compensation for this,
2751 // here we apply the "should not inline" mark in cases when the loop
2752 // could potentially reach the `MaxBlockVisitOnPath` limit without the
2753 // "don't assume third iteration" logic. This slightly overcompensates
2754 // (activates if the third iteration can be entered, and will not
2755 // recognize cases where the fourth iteration would't be completed), but
2756 // should be good enough for practical purposes.
2757 if (!SF->inTopFrame()) {
2758 Engine.FunctionSummaries->markShouldNotInline(D: SF->getDecl());
2759 }
2760 }
2761 }
2762
2763 if (StFalse) {
2764 // In a loop, if both branches are feasible (i.e. the analyzer doesn't
2765 // understand the loop condition), we are before the first iteration and
2766 // the analyzer option `assume-at-least-one-iteration` is set to `true`,
2767 // then avoid creating the execution path where the loop is skipped.
2768 //
2769 // In some situations this "loop is skipped" execution path is an
2770 // important corner case that may evade the notice of the developer and
2771 // hide significant bugs -- however, there are also many situations where
2772 // it's guaranteed that at least one iteration will happen (e.g. some
2773 // data structure is always nonempty), but the analyzer cannot realize
2774 // this and will produce false positives when it assumes that the loop is
2775 // skipped.
2776 bool BeforeFirstIteration = IterationsCompletedInLoop == std::optional{0};
2777 bool SkipFalseBranch = BothFeasible && BeforeFirstIteration &&
2778 AMgr.options.ShouldAssumeAtLeastOneIteration;
2779 if (!SkipFalseBranch && DstF) {
2780 BlockEdge BE(getCurrBlock(), DstF, SF);
2781 Dst.insert(N: Engine.makeNode(Loc: BE, State: StFalse, Pred: PredN));
2782 }
2783 }
2784 }
2785}
2786
2787/// The GDM component containing the set of global variables which have been
2788/// previously initialized with explicit initializers.
2789REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,
2790 llvm::ImmutableSet<const VarDecl *>)
2791
2792void ExprEngine::processStaticInitializer(const DeclStmt *DS,
2793 ExplodedNode *Pred,
2794 ExplodedNodeSet &Dst,
2795 const CFGBlock *DstT,
2796 const CFGBlock *DstF) {
2797 const auto *VD = cast<VarDecl>(Val: DS->getSingleDecl());
2798 ProgramStateRef State = Pred->getState();
2799 bool InitHasRun = State->contains<InitializedGlobalsSet>(key: VD);
2800 if (!InitHasRun)
2801 State = State->add<InitializedGlobalsSet>(K: VD);
2802
2803 if (const CFGBlock *DstBlock = InitHasRun ? DstT : DstF) {
2804 BlockEdge BE(getCurrBlock(), DstBlock, Pred->getStackFrame());
2805 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred));
2806 }
2807}
2808
2809/// processIndirectGoto - Called by CoreEngine. Used to generate successor
2810/// nodes by processing the 'effects' of a computed goto jump.
2811void ExprEngine::processIndirectGoto(ExplodedNodeSet &Dst, const Expr *Tgt,
2812 const CFGBlock *Dispatch,
2813 ExplodedNode *Pred) {
2814 ProgramStateRef State = Pred->getState();
2815 SVal V = State->getSVal(E: Tgt, SF: getCurrStackFrame());
2816
2817 // We cannot dispatch anywhere if the label is undefined, NULL or some other
2818 // concrete number.
2819 // FIXME: Emit a warning in this situation.
2820 if (isa<UndefinedVal, loc::ConcreteInt>(Val: V))
2821 return;
2822
2823 // If 'V' is the address of a concrete goto label (on this execution path),
2824 // then only transition along the edge to that label.
2825 // FIXME: Implement dispatch for symbolic pointers, utilizing information
2826 // that they are equal or not equal to pointers to a certain goto label.
2827 const LabelDecl *L = nullptr;
2828 if (auto LV = V.getAs<loc::GotoLabel>())
2829 L = LV->getLabel();
2830
2831 // Dispatch to the label 'L' or to all labels if 'L' is null.
2832 for (const CFGBlock *Succ : Dispatch->succs()) {
2833 if (!L || cast<LabelStmt>(Val: Succ->getLabel())->getDecl() == L) {
2834 // FIXME: If 'V' was a symbolic value, then record that on this execution
2835 // path it is equal to the address of the label leading to 'Succ'.
2836 BlockEdge BE(getCurrBlock(), Succ, Pred->getStackFrame());
2837 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred));
2838 }
2839 }
2840}
2841
2842void ExprEngine::processBeginOfFunction(ExplodedNode *Pred,
2843 ExplodedNodeSet &Dst,
2844 const BlockEdge &L) {
2845 getCheckerManager().runCheckersForBeginFunction(Dst, L, Pred, Eng&: *this);
2846}
2847
2848/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
2849/// nodes when the control reaches the end of a function.
2850void ExprEngine::processEndOfFunction(ExplodedNode *Pred,
2851 const ReturnStmt *RS) {
2852 ProgramStateRef State = Pred->getState();
2853
2854 if (!Pred->getStackFrame()->inTopFrame())
2855 State = finishArgumentConstruction(
2856 State, Call: *getStateManager().getCallEventManager().getCaller(
2857 CalleeSF: Pred->getStackFrame(), State: Pred->getState()));
2858
2859 // FIXME: We currently cannot assert that temporaries are clear, because
2860 // lifetime extended temporaries are not always modelled correctly. In some
2861 // cases when we materialize the temporary, we do
2862 // createTemporaryRegionIfNeeded(), and the region changes, and also the
2863 // respective destructor becomes automatic from temporary. So for now clean up
2864 // the state manually before asserting. Ideally, this braced block of code
2865 // should go away.
2866 {
2867 const StackFrame *FromSF = Pred->getStackFrame();
2868 const StackFrame *ToSF = FromSF->getParent();
2869 const StackFrame *SF = FromSF;
2870 while (SF != ToSF) {
2871 assert(SF && "ToSF must be a parent of FromSF!");
2872 for (auto I : State->get<ObjectsUnderConstruction>())
2873 if (I.first.getStackFrame() == SF) {
2874 // The comment above only pardons us for not cleaning up a
2875 // temporary destructor. If any other statements are found here,
2876 // it must be a separate problem.
2877 assert(I.first.getItem().getKind() ==
2878 ConstructionContextItem::TemporaryDestructorKind ||
2879 I.first.getItem().getKind() ==
2880 ConstructionContextItem::ElidedDestructorKind);
2881 State = State->remove<ObjectsUnderConstruction>(K: I.first);
2882 }
2883 SF = SF->getParent();
2884 }
2885 }
2886
2887 // Perform the transition with cleanups.
2888 if (State != Pred->getState()) {
2889 Pred = Engine.makeNode(Loc: Pred->getLocation(), State, Pred);
2890 if (!Pred) {
2891 // The node with clean temporaries already exists. We might have reached
2892 // it on a path on which we initialize different temporaries.
2893 return;
2894 }
2895 }
2896
2897 assert(areAllObjectsFullyConstructed(Pred->getState(), Pred->getStackFrame(),
2898 Pred->getStackFrame()->getParent()));
2899 ExplodedNodeSet Dst;
2900 if (Pred->getStackFrame()->inTopFrame()) {
2901 // Remove dead symbols.
2902 ExplodedNodeSet AfterRemovedDead;
2903 removeDeadOnEndOfFunction(Pred, Dst&: AfterRemovedDead);
2904
2905 // Notify checkers.
2906 for (const auto I : AfterRemovedDead)
2907 getCheckerManager().runCheckersForEndFunction(Dst, Pred: I, Eng&: *this, RS);
2908 } else {
2909 getCheckerManager().runCheckersForEndFunction(Dst, Pred, Eng&: *this, RS);
2910 }
2911
2912 Engine.enqueueEndOfFunction(Set&: Dst, RS);
2913}
2914
2915/// ProcessSwitch - Called by CoreEngine. Used to generate successor
2916/// nodes by processing the 'effects' of a switch statement.
2917void ExprEngine::processSwitch(const SwitchStmt *Switch, ExplodedNode *Pred,
2918 ExplodedNodeSet &Dst) {
2919 const ASTContext &ACtx = getContext();
2920 const StackFrame *SF = Pred->getStackFrame();
2921 const Expr *Condition = Switch->getCond();
2922
2923 // The block that is terminated by the switch statement.
2924 const CFGBlock *SwitchBlock = getCurrBlock();
2925 // Note that successors may be null if they are pruned as unreachable.
2926 assert(SwitchBlock->succ_size() && "Switch must have at least one successor");
2927 // The reversed iteration order is present since the beginning, when in 2008
2928 // commit 80ebc1d1c95704b0ff0386b3a3cbc8b3ff960654 added support for handling
2929 // switch statements. I don't see any advantage over regular forward
2930 // iteration -- but switching the order would perturb the insertion order of
2931 // the work list and therefore the analysis results.
2932 llvm::iterator_range<CFGBlock::const_succ_reverse_iterator> CaseBlocks(
2933 SwitchBlock->succ_rbegin() + 1, SwitchBlock->succ_rend());
2934 const CFGBlock *DefaultBlock = *SwitchBlock->succ_rbegin();
2935
2936 ExplodedNodeSet CheckersOutSet;
2937
2938 getCheckerManager().runCheckersForBranchCondition(
2939 condition: Condition->IgnoreParens(), Dst&: CheckersOutSet, Pred, Eng&: *this);
2940
2941 for (ExplodedNode *Node : CheckersOutSet) {
2942 ProgramStateRef State = Node->getState();
2943
2944 SVal CondV = State->getSVal(E: Condition, SF);
2945 if (CondV.isUndef()) {
2946 // This can only happen if core.uninitialized.Branch is disabled.
2947 continue;
2948 }
2949 std::optional<NonLoc> CondNL = CondV.getAs<NonLoc>();
2950
2951 for (const CFGBlock *CaseBlock : CaseBlocks) {
2952 // Successor may be pruned out during CFG construction.
2953 if (!CaseBlock)
2954 continue;
2955
2956 const CaseStmt *Case = cast<CaseStmt>(Val: CaseBlock->getLabel());
2957
2958 // Evaluate the LHS of the case value.
2959 llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(Ctx: ACtx);
2960 assert(V1.getBitWidth() ==
2961 getContext().getIntWidth(Condition->getType()));
2962
2963 // Get the RHS of the case, if it exists.
2964 llvm::APSInt V2;
2965 if (const Expr *E = Case->getRHS())
2966 V2 = E->EvaluateKnownConstInt(Ctx: ACtx);
2967 else
2968 V2 = V1;
2969
2970 ProgramStateRef StateMatching;
2971 if (CondNL) {
2972 // Split the state: this "case:" matches / does not match.
2973 std::tie(args&: StateMatching, args&: State) =
2974 State->assumeInclusiveRange(Val: *CondNL, From: V1, To: V2);
2975 } else {
2976 // The switch condition is UnknownVal, so we enter each "case:" without
2977 // any state update.
2978 StateMatching = State;
2979 }
2980
2981 if (StateMatching) {
2982 BlockEdge BE(SwitchBlock, CaseBlock, SF);
2983 Dst.insert(N: Engine.makeNode(Loc: BE, State: StateMatching, Pred: Node));
2984 }
2985
2986 // If _not_ entering the current case is infeasible, then we are done
2987 // with processing the paths through the current Node.
2988 if (!State)
2989 break;
2990 }
2991 if (!State)
2992 continue;
2993
2994 // The default block may be null if it is "optimized out" by CFG creation.
2995 if (!DefaultBlock)
2996 continue;
2997
2998 // If we have switch(enum value), the default branch is not
2999 // feasible if all of the enum constants not covered by 'case:' statements
3000 // are not feasible values for the switch condition.
3001 //
3002 // Note that this isn't as accurate as it could be. Even if there isn't
3003 // a case for a particular enum value as long as that enum value isn't
3004 // feasible then it shouldn't be considered for making 'default:' reachable.
3005 if (Condition->IgnoreParenImpCasts()->getType()->isEnumeralType()) {
3006 if (Switch->isAllEnumCasesCovered())
3007 continue;
3008 }
3009
3010 BlockEdge BE(SwitchBlock, DefaultBlock, SF);
3011 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred: Node));
3012 }
3013}
3014
3015//===----------------------------------------------------------------------===//
3016// Transfer functions: Loads and stores.
3017//===----------------------------------------------------------------------===//
3018
3019void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
3020 ExplodedNode *Pred,
3021 ExplodedNodeSet &Dst) {
3022 ProgramStateRef state = Pred->getState();
3023 const StackFrame *SF = Pred->getStackFrame();
3024
3025 auto resolveAsLambdaCapturedVar =
3026 [&](const ValueDecl *VD) -> std::optional<std::pair<SVal, QualType>> {
3027 const auto *MD = dyn_cast<CXXMethodDecl>(Val: SF->getDecl());
3028 const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Val: Ex);
3029 if (AMgr.options.ShouldInlineLambdas && DeclRefEx &&
3030 DeclRefEx->refersToEnclosingVariableOrCapture() && MD &&
3031 MD->getParent()->isLambda()) {
3032 // Lookup the field of the lambda.
3033 const CXXRecordDecl *CXXRec = MD->getParent();
3034 llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
3035 FieldDecl *LambdaThisCaptureField;
3036 CXXRec->getCaptureFields(Captures&: LambdaCaptureFields, ThisCapture&: LambdaThisCaptureField);
3037
3038 // Sema follows a sequence of complex rules to determine whether the
3039 // variable should be captured.
3040 if (const FieldDecl *FD = LambdaCaptureFields[VD]) {
3041 Loc CXXThis = svalBuilder.getCXXThis(D: MD, SF);
3042 SVal CXXThisVal = state->getSVal(LV: CXXThis);
3043 return std::make_pair(x: state->getLValue(decl: FD, Base: CXXThisVal), y: FD->getType());
3044 }
3045 }
3046
3047 return std::nullopt;
3048 };
3049
3050 if (const auto *VD = dyn_cast<VarDecl>(Val: D)) {
3051 // C permits "extern void v", and if you cast the address to a valid type,
3052 // you can even do things with it. We simply pretend
3053 assert(Ex->isGLValue() || VD->getType()->isVoidType());
3054 std::optional<std::pair<SVal, QualType>> VInfo =
3055 resolveAsLambdaCapturedVar(VD);
3056
3057 if (!VInfo)
3058 VInfo = std::make_pair(x: state->getLValue(VD, SF), y: VD->getType());
3059
3060 SVal V = VInfo->first;
3061 bool IsReference = VInfo->second->isReferenceType();
3062
3063 // For references, the 'lvalue' is the pointer address stored in the
3064 // reference region.
3065 if (IsReference) {
3066 if (const MemRegion *R = V.getAsRegion())
3067 V = state->getSVal(R);
3068 else
3069 V = UnknownVal();
3070 }
3071
3072 Dst.insert(
3073 N: Engine.makeNodeWithBinding(Pred, E: Ex, V, K: ProgramPoint::PostLValueKind));
3074 return;
3075 }
3076 if (const auto *ED = dyn_cast<EnumConstantDecl>(Val: D)) {
3077 assert(!Ex->isGLValue());
3078 SVal V = svalBuilder.makeIntVal(integer: ED->getInitVal());
3079 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: Ex, V));
3080 return;
3081 }
3082 if (const auto *FD = dyn_cast<FunctionDecl>(Val: D)) {
3083 SVal V = svalBuilder.getFunctionPointer(func: FD);
3084 Dst.insert(
3085 N: Engine.makeNodeWithBinding(Pred, E: Ex, V, K: ProgramPoint::PostLValueKind));
3086 return;
3087 }
3088 if (isa<FieldDecl, IndirectFieldDecl>(Val: D)) {
3089 // Delegate all work related to pointer to members to the surrounding
3090 // operator&.
3091 Dst.insert(N: Pred);
3092 return;
3093 }
3094 if (const auto *BD = dyn_cast<BindingDecl>(Val: D)) {
3095 // Handle structured bindings captured by lambda.
3096 if (std::optional<std::pair<SVal, QualType>> VInfo =
3097 resolveAsLambdaCapturedVar(BD)) {
3098 auto [V, T] = VInfo.value();
3099
3100 if (T->isReferenceType()) {
3101 if (const MemRegion *R = V.getAsRegion())
3102 V = state->getSVal(R);
3103 else
3104 V = UnknownVal();
3105 }
3106
3107 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: Ex, V,
3108 K: ProgramPoint::PostLValueKind));
3109 return;
3110 }
3111
3112 const auto *DD = cast<DecompositionDecl>(Val: BD->getDecomposedDecl());
3113
3114 SVal Base = state->getLValue(VD: DD, SF);
3115 if (DD->getType()->isReferenceType()) {
3116 if (const MemRegion *R = Base.getAsRegion())
3117 Base = state->getSVal(R);
3118 else
3119 Base = UnknownVal();
3120 }
3121
3122 SVal V = UnknownVal();
3123
3124 // Handle binding to data members
3125 if (const auto *ME = dyn_cast<MemberExpr>(Val: BD->getBinding())) {
3126 const auto *Field = cast<FieldDecl>(Val: ME->getMemberDecl());
3127 V = state->getLValue(decl: Field, Base);
3128 }
3129 // Handle binding to arrays
3130 else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Val: BD->getBinding())) {
3131 SVal Idx = state->getSVal(E: ASE->getIdx(), SF);
3132
3133 // Note: the index of an element in a structured binding is automatically
3134 // created and it is a unique identifier of the specific element. Thus it
3135 // cannot be a value that varies at runtime.
3136 assert(Idx.isConstant() && "BindingDecl array index is not a constant!");
3137
3138 V = state->getLValue(ElementType: BD->getType(), Idx, Base);
3139 }
3140 // Handle binding to tuple-like structures
3141 else if (const auto *HV = BD->getHoldingVar()) {
3142 V = state->getLValue(VD: HV, SF);
3143
3144 if (HV->getType()->isReferenceType()) {
3145 if (const MemRegion *R = V.getAsRegion())
3146 V = state->getSVal(R);
3147 else
3148 V = UnknownVal();
3149 }
3150 } else
3151 llvm_unreachable("An unknown case of structured binding encountered!");
3152
3153 // In case of tuple-like types the references are already handled, so we
3154 // don't want to handle them again.
3155 if (BD->getType()->isReferenceType() && !BD->getHoldingVar()) {
3156 if (const MemRegion *R = V.getAsRegion())
3157 V = state->getSVal(R);
3158 else
3159 V = UnknownVal();
3160 }
3161
3162 Dst.insert(
3163 N: Engine.makeNodeWithBinding(Pred, E: Ex, V, K: ProgramPoint::PostLValueKind));
3164 return;
3165 }
3166
3167 if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(Val: D)) {
3168 // FIXME: We should meaningfully implement this.
3169 (void)TPO;
3170 Dst.insert(N: Pred);
3171 return;
3172 }
3173
3174 llvm_unreachable("Support for this Decl not implemented.");
3175}
3176
3177/// VisitArrayInitLoopExpr - Transfer function for array init loop.
3178void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex,
3179 ExplodedNode *Pred,
3180 ExplodedNodeSet &Dst) {
3181 const Expr *Arr = Ex->getCommonExpr()->getSourceExpr();
3182
3183 ExplodedNodeSet CheckerPreStmt;
3184 getCheckerManager().runCheckersForPreStmt(Dst&: CheckerPreStmt, Src: Pred, S: Ex, Eng&: *this);
3185
3186 ExplodedNodeSet EvalSet;
3187 if (isa<CXXConstructExpr>(Val: Ex->getSubExpr())) {
3188 // The constructor visitor has already handled everything, so let's skip
3189 // forward to PostStmt handling by clearing the range of the 'for' loop.
3190 EvalSet.insert(S: CheckerPreStmt);
3191 CheckerPreStmt.clear();
3192 }
3193
3194 for (auto *Node : CheckerPreStmt) {
3195 const StackFrame *SF = Node->getStackFrame();
3196 ProgramStateRef state = Node->getState();
3197
3198 SVal Base = UnknownVal();
3199
3200 // As in case of this expression the sub-expressions are not visited by any
3201 // other transfer functions, they are handled by matching their AST.
3202
3203 // Case of implicit copy or move ctor of object with array member
3204 //
3205 // Note: ExprEngine::VisitMemberExpr is not able to bind the array to the
3206 // environment.
3207 //
3208 // struct S {
3209 // int arr[2];
3210 // };
3211 //
3212 //
3213 // S a;
3214 // S b = a;
3215 //
3216 // The AST in case of a *copy constructor* looks like this:
3217 // ArrayInitLoopExpr
3218 // |-OpaqueValueExpr
3219 // | `-MemberExpr <-- match this
3220 // | `-DeclRefExpr
3221 // ` ...
3222 //
3223 //
3224 // S c;
3225 // S d = std::move(d);
3226 //
3227 // In case of a *move constructor* the resulting AST looks like:
3228 // ArrayInitLoopExpr
3229 // |-OpaqueValueExpr
3230 // | `-MemberExpr <-- match this first
3231 // | `-CXXStaticCastExpr <-- match this after
3232 // | `-DeclRefExpr
3233 // ` ...
3234 if (const auto *ME = dyn_cast<MemberExpr>(Val: Arr)) {
3235 Expr *MEBase = ME->getBase();
3236
3237 // Move ctor
3238 if (auto CXXSCE = dyn_cast<CXXStaticCastExpr>(Val: MEBase)) {
3239 MEBase = CXXSCE->getSubExpr();
3240 }
3241
3242 auto ObjDeclExpr = cast<DeclRefExpr>(Val: MEBase);
3243 SVal Obj = state->getLValue(VD: cast<VarDecl>(Val: ObjDeclExpr->getDecl()), SF);
3244
3245 Base = state->getLValue(decl: cast<FieldDecl>(Val: ME->getMemberDecl()), Base: Obj);
3246 }
3247
3248 // Case of lambda capture and decomposition declaration
3249 //
3250 // int arr[2];
3251 //
3252 // [arr]{ int a = arr[0]; }();
3253 // auto[a, b] = arr;
3254 //
3255 // In both of these cases the AST looks like the following:
3256 // ArrayInitLoopExpr
3257 // |-OpaqueValueExpr
3258 // | `-DeclRefExpr <-- match this
3259 // ` ...
3260 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Val: Arr))
3261 Base = state->getLValue(VD: cast<VarDecl>(Val: DRE->getDecl()), SF);
3262
3263 // Create a lazy compound value to the original array
3264 if (const MemRegion *R = Base.getAsRegion())
3265 Base = state->getSVal(R);
3266 else
3267 Base = UnknownVal();
3268
3269 EvalSet.insert(N: Engine.makeNodeWithBinding(Pred: Node, E: Ex, V: Base));
3270 }
3271
3272 getCheckerManager().runCheckersForPostStmt(Dst, Src: EvalSet, S: Ex, Eng&: *this);
3273}
3274
3275/// VisitArraySubscriptExpr - Transfer function for array accesses
3276void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A,
3277 ExplodedNode *Pred,
3278 ExplodedNodeSet &Dst){
3279 const Expr *Base = A->getBase()->IgnoreParens();
3280 const Expr *Idx = A->getIdx()->IgnoreParens();
3281
3282 ExplodedNodeSet CheckerPreStmt;
3283 getCheckerManager().runCheckersForPreStmt(Dst&: CheckerPreStmt, Src: Pred, S: A, Eng&: *this);
3284
3285 ExplodedNodeSet EvalSet;
3286
3287 bool IsVectorType = A->getBase()->getType()->isVectorType();
3288
3289 // The "like" case is for situations where C standard prohibits the type to
3290 // be an lvalue, e.g. taking the address of a subscript of an expression of
3291 // type "void *".
3292 bool IsGLValueLike = A->isGLValue() ||
3293 (A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus);
3294
3295 for (auto *Node : CheckerPreStmt) {
3296 const StackFrame *SF = Node->getStackFrame();
3297 ProgramStateRef state = Node->getState();
3298
3299 if (IsGLValueLike) {
3300 QualType T = A->getType();
3301
3302 // One of the forbidden LValue types! We still need to have sensible
3303 // symbolic locations to represent this stuff. Note that arithmetic on
3304 // void pointers is a GCC extension.
3305 if (T->isVoidType())
3306 T = getContext().CharTy;
3307
3308 SVal V = state->getLValue(ElementType: T, Idx: state->getSVal(E: Idx, SF),
3309 Base: state->getSVal(E: Base, SF));
3310 EvalSet.insert(
3311 N: Engine.makeNodeWithBinding(Pred: Node, E: A, V, K: ProgramPoint::PostLValueKind));
3312 } else if (IsVectorType) {
3313 // FIXME: non-glvalue vector reads are not modelled.
3314 EvalSet.insert(N: Engine.makePostStmtNode(S: A, State: state, Pred: Node));
3315 } else {
3316 llvm_unreachable("Array subscript should be an lValue when not \
3317a vector and not a forbidden lvalue type");
3318 }
3319 }
3320
3321 getCheckerManager().runCheckersForPostStmt(Dst, Src: EvalSet, S: A, Eng&: *this);
3322}
3323
3324/// VisitMemberExpr - Transfer function for member expressions.
3325void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
3326 ExplodedNodeSet &Dst) {
3327 // FIXME: Prechecks eventually go in ::Visit().
3328 ExplodedNodeSet CheckedSet;
3329 getCheckerManager().runCheckersForPreStmt(Dst&: CheckedSet, Src: Pred, S: M, Eng&: *this);
3330
3331 ExplodedNodeSet EvalSet;
3332 ValueDecl *Member = M->getMemberDecl();
3333
3334 // Handle static member variables and enum constants accessed via
3335 // member syntax.
3336 if (isa<VarDecl, EnumConstantDecl>(Val: Member)) {
3337 for (const auto I : CheckedSet)
3338 VisitCommonDeclRefExpr(Ex: M, D: Member, Pred: I, Dst&: EvalSet);
3339 } else {
3340
3341 for (const auto I : CheckedSet) {
3342 ProgramStateRef state = I->getState();
3343 const StackFrame *SF = I->getStackFrame();
3344 Expr *BaseExpr = M->getBase();
3345
3346 // Handle C++ method calls.
3347 if (const auto *MD = dyn_cast<CXXMethodDecl>(Val: Member)) {
3348 if (MD->isImplicitObjectMemberFunction())
3349 state = createTemporaryRegionIfNeeded(State: state, SF, InitWithAdjustments: BaseExpr);
3350
3351 SVal MDVal = svalBuilder.getFunctionPointer(func: MD);
3352
3353 EvalSet.insert(N: Engine.makeNodeWithBinding(Pred: I, E: M, V: MDVal, State: state));
3354 continue;
3355 }
3356
3357 // Handle regular struct fields / member variables.
3358 const SubRegion *MR = nullptr;
3359 state = createTemporaryRegionIfNeeded(State: state, SF, InitWithAdjustments: BaseExpr,
3360 /*Result=*/nullptr,
3361 /*OutRegionWithAdjustments=*/&MR);
3362 SVal baseExprVal =
3363 MR ? loc::MemRegionVal(MR) : state->getSVal(E: BaseExpr, SF);
3364
3365 // FIXME: Copied from RegionStoreManager::bind()
3366 if (const auto *SR =
3367 dyn_cast_or_null<SymbolicRegion>(Val: baseExprVal.getAsRegion())) {
3368 QualType T = SR->getPointeeStaticType();
3369 baseExprVal =
3370 loc::MemRegionVal(getStoreManager().GetElementZeroRegion(R: SR, T));
3371 }
3372
3373 const auto *field = cast<FieldDecl>(Val: Member);
3374 SVal L = state->getLValue(decl: field, Base: baseExprVal);
3375
3376 if (M->isGLValue() || M->getType()->isArrayType()) {
3377 // We special-case rvalues of array type because the analyzer cannot
3378 // reason about them, since we expect all regions to be wrapped in Locs.
3379 // We instead treat these as lvalues and assume that they will decay to
3380 // pointers as soon as they are used.
3381 if (!M->isGLValue()) {
3382 assert(M->getType()->isArrayType());
3383 const auto *PE =
3384 dyn_cast<ImplicitCastExpr>(Val: I->getParentMap().getParentIgnoreParens(S: M));
3385 if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) {
3386 llvm_unreachable("should always be wrapped in ArrayToPointerDecay");
3387 }
3388 }
3389
3390 if (field->getType()->isReferenceType()) {
3391 if (const MemRegion *R = L.getAsRegion())
3392 L = state->getSVal(R);
3393 else
3394 L = UnknownVal();
3395 }
3396
3397 EvalSet.insert(N: Engine.makeNodeWithBinding(
3398 Pred: I, E: M, V: L, State: state, K: ProgramPoint::PostLValueKind));
3399 } else {
3400 evalLoad(Dst&: EvalSet, NodeEx: M, BoundExpr: M, Pred: I, St: state, location: L);
3401 }
3402 }
3403 }
3404
3405 getCheckerManager().runCheckersForPostStmt(Dst, Src: EvalSet, S: M, Eng&: *this);
3406}
3407
3408void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
3409 ExplodedNodeSet &Dst) {
3410 ExplodedNodeSet AfterPreSet;
3411 getCheckerManager().runCheckersForPreStmt(Dst&: AfterPreSet, Src: Pred, S: AE, Eng&: *this);
3412
3413 // For now, treat all the arguments to C11 atomics as escaping.
3414 // FIXME: Ideally we should model the behavior of the atomics precisely here.
3415
3416 ExplodedNodeSet AfterInvalidateSet;
3417
3418 for (const auto I : AfterPreSet) {
3419 ProgramStateRef State = I->getState();
3420 const StackFrame *SF = I->getStackFrame();
3421
3422 SmallVector<SVal, 8> ValuesToInvalidate;
3423 for (const Stmt *SubExpr : AE->children()) {
3424 SVal SubExprVal = State->getSVal(E: cast<Expr>(Val: SubExpr), SF);
3425 ValuesToInvalidate.push_back(Elt: SubExprVal);
3426 }
3427
3428 State = State->invalidateRegions(Values: ValuesToInvalidate, Elem: getCFGElementRef(),
3429 BlockCount: getNumVisitedCurrent(), SF,
3430 /*CausedByPointerEscape*/ CausesPointerEscape: true,
3431 /*Symbols=*/IS: nullptr);
3432
3433 AfterInvalidateSet.insert(
3434 N: Engine.makeNodeWithBinding(Pred: I, E: AE, V: UnknownVal(), State));
3435 }
3436
3437 getCheckerManager().runCheckersForPostStmt(Dst, Src: AfterInvalidateSet, S: AE, Eng&: *this);
3438}
3439
3440// A value escapes in four possible cases:
3441// (1) We are binding to something that is not a memory region.
3442// (2) We are binding to a MemRegion that does not have stack storage.
3443// (3) We are binding to a top-level parameter region with a non-trivial
3444// destructor. We won't see the destructor during analysis, but it's there.
3445// (4) We are binding to a MemRegion with stack storage that the store
3446// does not understand.
3447ProgramStateRef ExprEngine::processPointerEscapedOnBind(
3448 ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals,
3449 const StackFrame *SF, PointerEscapeKind Kind, const CallEvent *Call) {
3450 SmallVector<SVal, 8> Escaped;
3451 for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
3452 // Cases (1) and (2).
3453 const MemRegion *MR = LocAndVal.first.getAsRegion();
3454 const MemSpaceRegion *Space = MR ? MR->getMemorySpace(State) : nullptr;
3455 if (!MR || !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(Val: Space)) {
3456 Escaped.push_back(Elt: LocAndVal.second);
3457 continue;
3458 }
3459
3460 // Case (3).
3461 if (const auto *VR = dyn_cast<VarRegion>(Val: MR->getBaseRegion()))
3462 if (isa<StackArgumentsSpaceRegion>(Val: Space) &&
3463 VR->getStackFrame()->inTopFrame())
3464 if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
3465 if (!RD->hasTrivialDestructor()) {
3466 Escaped.push_back(Elt: LocAndVal.second);
3467 continue;
3468 }
3469
3470 // Case (4): in order to test that, generate a new state with the binding
3471 // added. If it is the same state, then it escapes (since the store cannot
3472 // represent the binding).
3473 // Do this only if we know that the store is not supposed to generate the
3474 // same state.
3475 SVal StoredVal = State->getSVal(R: MR);
3476 if (StoredVal != LocAndVal.second)
3477 if (State ==
3478 (State->bindLoc(location: loc::MemRegionVal(MR), V: LocAndVal.second, SF)))
3479 Escaped.push_back(Elt: LocAndVal.second);
3480 }
3481
3482 if (Escaped.empty())
3483 return State;
3484
3485 return escapeValues(State, Vs: Escaped, K: Kind, Call);
3486}
3487
3488ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
3489 SVal Loc, SVal Val,
3490 const StackFrame *SF) {
3491 std::pair<SVal, SVal> LocAndVal(Loc, Val);
3492 return processPointerEscapedOnBind(State, LocAndVals: LocAndVal, SF, Kind: PSK_EscapeOnBind,
3493 Call: nullptr);
3494}
3495
3496ProgramStateRef
3497ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
3498 const InvalidatedSymbols *Invalidated,
3499 ArrayRef<const MemRegion *> ExplicitRegions,
3500 const CallEvent *Call,
3501 RegionAndSymbolInvalidationTraits &ITraits) {
3502 if (!Invalidated || Invalidated->empty())
3503 return State;
3504
3505 if (!Call)
3506 return getCheckerManager().runCheckersForPointerEscape(State,
3507 Escaped: *Invalidated,
3508 Call: nullptr,
3509 Kind: PSK_EscapeOther,
3510 ITraits: &ITraits);
3511
3512 // If the symbols were invalidated by a call, we want to find out which ones
3513 // were invalidated directly due to being arguments to the call.
3514 InvalidatedSymbols SymbolsDirectlyInvalidated;
3515 for (const auto I : ExplicitRegions) {
3516 if (const SymbolicRegion *R = I->StripCasts()->getAs<SymbolicRegion>())
3517 SymbolsDirectlyInvalidated.insert(V: R->getSymbol());
3518 }
3519
3520 InvalidatedSymbols SymbolsIndirectlyInvalidated;
3521 for (const auto &sym : *Invalidated) {
3522 if (SymbolsDirectlyInvalidated.count(V: sym))
3523 continue;
3524 SymbolsIndirectlyInvalidated.insert(V: sym);
3525 }
3526
3527 if (!SymbolsDirectlyInvalidated.empty())
3528 State = getCheckerManager().runCheckersForPointerEscape(State,
3529 Escaped: SymbolsDirectlyInvalidated, Call, Kind: PSK_DirectEscapeOnCall, ITraits: &ITraits);
3530
3531 // Notify about the symbols that get indirectly invalidated by the call.
3532 if (!SymbolsIndirectlyInvalidated.empty())
3533 State = getCheckerManager().runCheckersForPointerEscape(State,
3534 Escaped: SymbolsIndirectlyInvalidated, Call, Kind: PSK_IndirectEscapeOnCall, ITraits: &ITraits);
3535
3536 return State;
3537}
3538
3539/// evalBind - Handle the semantics of binding a value to a specific location.
3540/// This method is used by evalStore, VisitDeclStmt, and others.
3541void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
3542 ExplodedNode *Pred, SVal Location, SVal Val,
3543 bool AtDeclInit, const ProgramPoint *PP) {
3544
3545 // It may be a Loc, UnknownVal or perhaps UndefinedVal.
3546 assert(!isa<NonLoc>(Location) && "evalBind location should not be NonLoc!");
3547
3548 const StackFrame *SF = Pred->getStackFrame();
3549 PostStmt DefaultPP(StoreE, SF);
3550
3551 if (!PP)
3552 PP = &DefaultPP;
3553
3554 // Do a previsit of the bind.
3555 ExplodedNodeSet CheckedSet;
3556 getCheckerManager().runCheckersForBind(Dst&: CheckedSet, Src: Pred, location: Location, val: Val,
3557 S: StoreE, AtDeclInit, Eng&: *this, PP: *PP);
3558
3559 for (ExplodedNode *PredI : CheckedSet) {
3560 ProgramStateRef State = PredI->getState();
3561
3562 // Check and record that 'Val' may escape:
3563 State = processPointerEscapedOnBind(State, Loc: Location, Val, SF);
3564
3565 if (auto AsLoc = Location.getAs<Loc>()) {
3566 // When binding the value, pass on the hint that this is a
3567 // initialization. For initializations, we do not need to inform clients
3568 // of region changes.
3569 State = State->bindLoc(location: *AsLoc, V: Val, SF, /*notifyChanges=*/!AtDeclInit);
3570 }
3571
3572 PostStore PS(StoreE, SF, Location.getAsRegion(), /*tag=*/nullptr);
3573 Dst.insert(N: Engine.makeNode(Loc: PS, State, Pred: PredI));
3574 }
3575}
3576
3577/// evalStore - Handle the semantics of a store via an assignment.
3578/// @param Dst The node set to store generated state nodes
3579/// @param AssignE The assignment expression if the store happens in an
3580/// assignment.
3581/// @param LocationE The location expression that is stored to.
3582/// @param state The current simulation state
3583/// @param location The location to store the value
3584/// @param Val The value to be stored
3585void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
3586 const Expr *LocationE,
3587 ExplodedNode *Pred,
3588 ProgramStateRef state, SVal location, SVal Val,
3589 const ProgramPointTag *tag) {
3590 // Proceed with the store. We use AssignE as the anchor for the PostStore
3591 // ProgramPoint if it is non-NULL, and LocationE otherwise.
3592 const Expr *StoreE = AssignE ? AssignE : LocationE;
3593
3594 // Evaluate the location (checks for bad dereferences).
3595 ExplodedNodeSet Tmp;
3596 evalLocation(Dst&: Tmp, NodeEx: AssignE, BoundEx: LocationE, Pred, St: state, location, isLoad: false);
3597
3598 if (Tmp.empty())
3599 return;
3600
3601 if (location.isUndef())
3602 return;
3603
3604 for (const auto I : Tmp)
3605 evalBind(Dst, StoreE, Pred: I, Location: location, Val, AtDeclInit: false);
3606}
3607
3608void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
3609 const Expr *NodeEx,
3610 const Expr *BoundEx,
3611 ExplodedNode *Pred,
3612 ProgramStateRef state,
3613 SVal location,
3614 const ProgramPointTag *tag,
3615 QualType LoadTy) {
3616 assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
3617 assert(NodeEx);
3618 assert(BoundEx);
3619 // Evaluate the location (checks for bad dereferences).
3620 ExplodedNodeSet Tmp;
3621 evalLocation(Dst&: Tmp, NodeEx, BoundEx, Pred, St: state, location, isLoad: true);
3622 if (Tmp.empty())
3623 return;
3624
3625 if (location.isUndef()) {
3626 Dst.insert(S: Tmp);
3627 return;
3628 }
3629
3630 // Proceed with the load.
3631 for (const auto I : Tmp) {
3632 state = I->getState();
3633
3634 SVal V = UnknownVal();
3635 if (location.isValid()) {
3636 if (LoadTy.isNull())
3637 LoadTy = BoundEx->getType();
3638 V = state->getSVal(LV: location.castAs<Loc>(), T: LoadTy);
3639 }
3640
3641 const auto *SF = I->getStackFrame();
3642 PostLoad Loc(NodeEx, SF, tag);
3643 Dst.insert(N: Engine.makeNode(Loc, State: state->BindExpr(E: BoundEx, SF, V), Pred: I));
3644 }
3645}
3646
3647void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *NodeEx,
3648 const Stmt *BoundEx, ExplodedNode *Pred,
3649 ProgramStateRef state, SVal location,
3650 bool isLoad) {
3651 // Early checks for performance reason.
3652 if (location.isUnknown()) {
3653 Dst.insert(N: Pred);
3654 return;
3655 }
3656
3657 ExplodedNodeSet Src;
3658 if (Pred->getState() == state) {
3659 Src.insert(N: Pred);
3660 } else {
3661 // Associate this new state with an ExplodedNode.
3662 // FIXME: If I pass null tag, the graph is incorrect, e.g for
3663 // int *p;
3664 // p = 0;
3665 // *p = 0xDEADBEEF;
3666 // "p = 0" is not noted as "Null pointer value stored to 'p'" but
3667 // instead "int *p" is noted as
3668 // "Variable 'p' initialized to a null pointer value"
3669
3670 static SimpleProgramPointTag tag(TagProviderName, "Location");
3671 PostStmt Loc(NodeEx, Pred->getStackFrame(), &tag);
3672 Src.insert(N: Engine.makeNode(Loc, State: state, Pred));
3673 }
3674
3675 ExplodedNodeSet Tmp;
3676 getCheckerManager().runCheckersForLocation(Dst&: Tmp, Src, location, isLoad,
3677 NodeEx, BoundEx, Eng&: *this);
3678 Dst.insert(S: Tmp);
3679}
3680
3681std::pair<const ProgramPointTag *, const ProgramPointTag *>
3682ExprEngine::getEagerlyAssumeBifurcationTags() {
3683 static SimpleProgramPointTag TrueTag(TagProviderName, "Eagerly Assume True"),
3684 FalseTag(TagProviderName, "Eagerly Assume False");
3685
3686 return std::make_pair(x: &TrueTag, y: &FalseTag);
3687}
3688
3689/// If the last EagerlyAssume attempt was successful (i.e. the true and false
3690/// cases were both feasible), this state trait stores the expression where it
3691/// happened; otherwise this holds nullptr.
3692REGISTER_TRAIT_WITH_PROGRAMSTATE(LastEagerlyAssumeExprIfSuccessful,
3693 const Expr *)
3694
3695void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst,
3696 ExplodedNodeSet &Src,
3697 const Expr *Ex) {
3698 for (ExplodedNode *Pred : Src) {
3699 const StackFrame *SF = Pred->getStackFrame();
3700 // Test if the previous node was as the same expression. This can happen
3701 // when the expression fails to evaluate to anything meaningful and
3702 // (as an optimization) we don't generate a node.
3703 ProgramPoint P = Pred->getLocation();
3704 if (!P.getAs<PostStmt>() || P.castAs<PostStmt>().getStmt() != Ex) {
3705 Dst.insert(N: Pred);
3706 continue;
3707 }
3708
3709 ProgramStateRef State = Pred->getState();
3710 State = State->set<LastEagerlyAssumeExprIfSuccessful>(nullptr);
3711 SVal V = State->getSVal(E: Ex, SF);
3712 std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
3713 if (SEV && SEV->isExpression()) {
3714 const auto &[TrueTag, FalseTag] = getEagerlyAssumeBifurcationTags();
3715
3716 auto [StateTrue, StateFalse] = State->assume(Cond: *SEV);
3717
3718 if (StateTrue && StateFalse) {
3719 StateTrue = StateTrue->set<LastEagerlyAssumeExprIfSuccessful>(Ex);
3720 StateFalse = StateFalse->set<LastEagerlyAssumeExprIfSuccessful>(Ex);
3721 }
3722
3723 // First assume that the condition is true.
3724 if (StateTrue) {
3725 SVal Val = svalBuilder.makeIntVal(integer: 1U, type: Ex->getType());
3726 StateTrue = StateTrue->BindExpr(E: Ex, SF, V: Val);
3727 PostStmt PostStmtTrue(Ex, SF, TrueTag);
3728 Dst.insert(N: Engine.makeNode(Loc: PostStmtTrue, State: StateTrue, Pred));
3729 }
3730
3731 // Next, assume that the condition is false.
3732 if (StateFalse) {
3733 SVal Val = svalBuilder.makeIntVal(integer: 0U, type: Ex->getType());
3734 StateFalse = StateFalse->BindExpr(E: Ex, SF, V: Val);
3735 PostStmt PostStmtFalse(Ex, SF, FalseTag);
3736 Dst.insert(N: Engine.makeNode(Loc: PostStmtFalse, State: StateFalse, Pred));
3737 }
3738 } else {
3739 Dst.insert(N: Pred);
3740 }
3741 }
3742}
3743
3744bool ExprEngine::didEagerlyAssumeBifurcateAt(ProgramStateRef State,
3745 const Expr *Ex) const {
3746 return Ex && State->get<LastEagerlyAssumeExprIfSuccessful>() == Ex;
3747}
3748
3749void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
3750 ExplodedNodeSet &Dst) {
3751 // We have processed both the inputs and the outputs. All of the outputs
3752 // should evaluate to Locs. Nuke all of their values.
3753
3754 // FIXME: Some day in the future it would be nice to allow a "plug-in"
3755 // which interprets the inline asm and stores proper results in the
3756 // outputs.
3757
3758 ProgramStateRef state = Pred->getState();
3759
3760 for (const Expr *O : A->outputs()) {
3761 SVal X = state->getSVal(E: O, SF: Pred->getStackFrame());
3762 assert(!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
3763
3764 if (std::optional<Loc> LV = X.getAs<Loc>())
3765 state = state->invalidateRegions(Values: *LV, Elem: getCFGElementRef(),
3766 BlockCount: getNumVisitedCurrent(),
3767 SF: Pred->getStackFrame(),
3768 /*CausedByPointerEscape=*/CausesPointerEscape: true);
3769 }
3770
3771 // Do not reason about locations passed inside inline assembly.
3772 for (const Expr *I : A->inputs()) {
3773 SVal X = state->getSVal(E: I, SF: Pred->getStackFrame());
3774
3775 if (std::optional<Loc> LV = X.getAs<Loc>())
3776 state = state->invalidateRegions(Values: *LV, Elem: getCFGElementRef(),
3777 BlockCount: getNumVisitedCurrent(),
3778 SF: Pred->getStackFrame(),
3779 /*CausedByPointerEscape=*/CausesPointerEscape: true);
3780 }
3781
3782 Dst.insert(N: Engine.makePostStmtNode(S: A, State: state, Pred));
3783}
3784
3785void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
3786 ExplodedNodeSet &Dst) {
3787 Dst.insert(N: Engine.makePostStmtNode(S: A, State: Pred->getState(), Pred));
3788}
3789
3790//===----------------------------------------------------------------------===//
3791// Visualization.
3792//===----------------------------------------------------------------------===//
3793
3794namespace llvm {
3795
3796template<>
3797struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
3798 DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
3799
3800 static bool nodeHasBugReport(const ExplodedNode *N) {
3801 BugReporter &BR = static_cast<ExprEngine &>(
3802 N->getState()->getStateManager().getOwningEngine()).getBugReporter();
3803
3804 for (const auto &Class : BR.equivalenceClasses()) {
3805 for (const auto &Report : Class.getReports()) {
3806 const auto *PR = dyn_cast<PathSensitiveBugReport>(Val: Report.get());
3807 if (!PR)
3808 continue;
3809 const ExplodedNode *EN = PR->getErrorNode();
3810 if (EN->getState() == N->getState() &&
3811 EN->getLocation() == N->getLocation())
3812 return true;
3813 }
3814 }
3815 return false;
3816 }
3817
3818 /// \p PreCallback: callback before break.
3819 /// \p PostCallback: callback after break.
3820 /// \p Stop: stop iteration if returns @c true
3821 /// \return Whether @c Stop ever returned @c true.
3822 static bool traverseHiddenNodes(
3823 const ExplodedNode *N,
3824 llvm::function_ref<void(const ExplodedNode *)> PreCallback,
3825 llvm::function_ref<void(const ExplodedNode *)> PostCallback,
3826 llvm::function_ref<bool(const ExplodedNode *)> Stop) {
3827 while (true) {
3828 PreCallback(N);
3829 if (Stop(N))
3830 return true;
3831
3832 if (N->succ_size() != 1 || !isNodeHidden(N: N->getFirstSucc(), G: nullptr))
3833 break;
3834 PostCallback(N);
3835
3836 N = N->getFirstSucc();
3837 }
3838 return false;
3839 }
3840
3841 static bool isNodeHidden(const ExplodedNode *N, const ExplodedGraph *G) {
3842 return N->isTrivial();
3843 }
3844
3845 static std::string getNodeLabel(const ExplodedNode *N, ExplodedGraph *G){
3846 std::string Buf;
3847 llvm::raw_string_ostream Out(Buf);
3848
3849 const bool IsDot = true;
3850 const unsigned int Space = 1;
3851 ProgramStateRef State = N->getState();
3852
3853 Out << "{ \"state_id\": " << State->getID()
3854 << ",\\l";
3855
3856 Indent(Out, Space, IsDot) << "\"program_points\": [\\l";
3857
3858 // Dump program point for all the previously skipped nodes.
3859 traverseHiddenNodes(
3860 N,
3861 PreCallback: [&](const ExplodedNode *OtherNode) {
3862 Indent(Out, Space: Space + 1, IsDot) << "{ ";
3863 OtherNode->getLocation().printJson(Out, /*NL=*/"\\l");
3864 Out << ", \"tag\": ";
3865 if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag())
3866 Out << '\"' << Tag->getDebugTag() << '\"';
3867 else
3868 Out << "null";
3869 Out << ", \"node_id\": " << OtherNode->getID() <<
3870 ", \"is_sink\": " << OtherNode->isSink() <<
3871 ", \"has_report\": " << nodeHasBugReport(N: OtherNode) << " }";
3872 },
3873 // Adds a comma and a new-line between each program point.
3874 PostCallback: [&](const ExplodedNode *) { Out << ",\\l"; },
3875 Stop: [&](const ExplodedNode *) { return false; });
3876
3877 Out << "\\l"; // Adds a new-line to the last program point.
3878 Indent(Out, Space, IsDot) << "],\\l";
3879
3880 State->printDOT(Out, SF: N->getStackFrame(), Space);
3881
3882 Out << "\\l}\\l";
3883 return Buf;
3884 }
3885};
3886
3887} // namespace llvm
3888
3889void ExprEngine::ViewGraph(bool trim) {
3890 std::string Filename = DumpGraph(trim);
3891 llvm::DisplayGraph(Filename, wait: false, program: llvm::GraphProgram::DOT);
3892}
3893
3894void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode *> Nodes) {
3895 std::string Filename = DumpGraph(Nodes);
3896 llvm::DisplayGraph(Filename, wait: false, program: llvm::GraphProgram::DOT);
3897}
3898
3899std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) {
3900 if (trim) {
3901 std::vector<const ExplodedNode *> Src;
3902
3903 // Iterate through the reports and get their nodes.
3904 for (const auto &Class : BR.equivalenceClasses()) {
3905 const auto *R =
3906 dyn_cast<PathSensitiveBugReport>(Val: Class.getReports()[0].get());
3907 if (!R)
3908 continue;
3909 const auto *N = const_cast<ExplodedNode *>(R->getErrorNode());
3910 Src.push_back(x: N);
3911 }
3912 return DumpGraph(Nodes: Src, Filename);
3913 }
3914
3915 // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
3916 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
3917 return llvm::WriteGraph(G: &G, Name: "ExprEngine", /*ShortNames=*/false,
3918 /*Title=*/"Exploded Graph",
3919 /*Filename=*/std::string(Filename));
3920}
3921
3922std::string ExprEngine::DumpGraph(ArrayRef<const ExplodedNode *> Nodes,
3923 StringRef Filename) {
3924 std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes));
3925
3926 if (!TrimmedG) {
3927 llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
3928 return "";
3929 }
3930
3931 // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
3932 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
3933 return llvm::WriteGraph(G: TrimmedG.get(), Name: "TrimmedExprEngine",
3934 /*ShortNames=*/false,
3935 /*Title=*/"Trimmed Exploded Graph",
3936 /*Filename=*/std::string(Filename));
3937}
3938
3939void *ProgramStateTrait<ReplayWithoutInlining>::GDMIndex() {
3940 static int index = 0;
3941 return &index;
3942}
3943
3944void ExprEngine::anchor() { }
3945
3946void ExprEngine::ConstructInitList(const Expr *E, ArrayRef<Expr *> Args,
3947 bool IsTransparent, ExplodedNode *Pred,
3948 ExplodedNodeSet &Dst) {
3949 assert((isa<InitListExpr, CXXParenListInitExpr>(E)));
3950
3951 const StackFrame *SF = Pred->getStackFrame();
3952
3953 ProgramStateRef S = Pred->getState();
3954 QualType T = E->getType().getCanonicalType();
3955
3956 bool IsCompound = T->isArrayType() || T->isRecordType() ||
3957 T->isAnyComplexType() || T->isVectorType();
3958
3959 SVal Val;
3960 if (Args.size() > 1 || (E->isPRValue() && IsCompound && !IsTransparent)) {
3961 llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
3962 for (Expr *E : llvm::reverse(C&: Args))
3963 ArgList = getBasicVals().prependSVal(X: S->getSVal(E, SF), L: ArgList);
3964
3965 Val = getSValBuilder().makeCompoundVal(type: T, vals: ArgList);
3966 } else if (Args.size() == 0) {
3967 Val = getSValBuilder().makeZeroVal(type: T);
3968 } else {
3969 Val = S->getSVal(E: Args.front(), SF);
3970 }
3971 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E, V: Val));
3972}
3973