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