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
1103namespace {
1104enum class VisitKind {
1105 Pre,
1106 Post,
1107};
1108}
1109
1110static bool shouldJustCallCheckers(const Stmt *S, VisitKind K) {
1111
1112 switch (S->getStmtClass()) {
1113
1114 default:
1115 return true;
1116
1117 // FIXME: Does not call checkers
1118 case Stmt::GNUNullExprClass:
1119 return false;
1120
1121 // FIXME: Does not call PostVisit checkers
1122 case Stmt::ObjCAtSynchronizedStmtClass:
1123 return K == VisitKind::Pre;
1124
1125 // FIXME: They do not call checkers
1126 case Expr::ConstantExprClass:
1127 case Stmt::ExprWithCleanupsClass:
1128 return false;
1129
1130 // FIXME: Does not call checkers
1131 case Stmt::MSAsmStmtClass:
1132 return false;
1133
1134 // FIXME: Does not call PreVisit checkers
1135 case Stmt::BlockExprClass:
1136 return K == VisitKind::Post;
1137
1138 // FIXME: Does not call PreVisit checkers
1139 // Currently the engine does not call PostVisit checkers when
1140 // lambda inlining is disabled, so K == PostVisitKind
1141 // cannot be returned here.
1142 case Stmt::LambdaExprClass:
1143 return false;
1144
1145 // Checkers are called manually with custom logic when this calls
1146 // VisitBinaryOperator, but calls no checkers during VisitLogicalExpr
1147 case Stmt::BinaryOperatorClass:
1148 return false;
1149
1150 // Checkers are called manually with custom logic in these cases
1151 // (VisitCallExpr)
1152 case Stmt::CXXOperatorCallExprClass:
1153 case Stmt::CallExprClass:
1154 case Stmt::CXXMemberCallExprClass:
1155 case Stmt::UserDefinedLiteralClass:
1156 return false;
1157
1158 // FIXME: Does not call checkers
1159 case Stmt::CXXCatchStmtClass:
1160 return false;
1161
1162 // Checkers are called manually with custom logic in these cases
1163 // (handleConstructor)
1164 case Stmt::CXXTemporaryObjectExprClass:
1165 case Stmt::CXXConstructExprClass:
1166 return false;
1167
1168 // Checkers are called manually with custom logic in this case
1169 // (handleConstructor)
1170 case Stmt::CXXInheritedCtorInitExprClass:
1171 return false;
1172
1173 // FIXME: Does not call checkers
1174 case Stmt::ChooseExprClass:
1175 return false;
1176
1177 // Checkers are called manually with custom logic in this case
1178 // (VisitBinaryOperator)
1179 case Stmt::CompoundAssignOperatorClass:
1180 return false;
1181
1182 // FIXME: Does not call checkers
1183 case Stmt::CompoundLiteralExprClass:
1184 return false;
1185
1186 // FIXME: These do not call checkers
1187 case Stmt::BinaryConditionalOperatorClass:
1188 case Stmt::ConditionalOperatorClass:
1189 return false;
1190
1191 // FIXME: Does not call checkers
1192 case Stmt::CXXThisExprClass:
1193 return false;
1194
1195 // FIXME: Does not call checkers
1196 case Stmt::DeclRefExprClass:
1197 return false;
1198
1199 // Checkers are called manually with custom logic in this case
1200 case Stmt::DeclStmtClass:
1201 return false;
1202
1203 // FIXME: These do not call checkers
1204 // (ConstructInitList)
1205 case Stmt::InitListExprClass:
1206 case Expr::CXXParenListInitExprClass:
1207 return false;
1208
1209 // FIXME: Does not call PreVisit checkers
1210 case Stmt::ObjCIvarRefExprClass:
1211 return K == VisitKind::Post;
1212
1213 // FIXME: Does not call PreVisit checkers
1214 case Stmt::ObjCForCollectionStmtClass:
1215 return K == VisitKind::Post;
1216
1217 // FIXME: Does not call checkers
1218 case Stmt::ObjCMessageExprClass:
1219 return false;
1220
1221 // FIXME: These do not call checkers
1222 case Stmt::ObjCAtThrowStmtClass:
1223 case Stmt::CXXThrowExprClass:
1224 return false;
1225
1226 // FIXME: Does not call PostVisit checkers
1227 case Stmt::ReturnStmtClass:
1228 return K == VisitKind::Pre;
1229
1230 // FIXME: Does not call checkers
1231 case Stmt::StmtExprClass:
1232 return false;
1233
1234 // Checkers are called manually with custom logic in this case
1235 case Stmt::UnaryOperatorClass:
1236 return false;
1237
1238 // FIXME: Does not call checkers
1239 case Stmt::PseudoObjectExprClass:
1240 return false;
1241
1242 // FIXME: Does not call checkers
1243 case Expr::ObjCIndirectCopyRestoreExprClass:
1244 return false;
1245 }
1246}
1247
1248void ExprEngine::ProcessStmt(const Stmt *currStmt, ExplodedNode *Pred) {
1249 // Reclaim any unnecessary nodes in the ExplodedGraph.
1250 G.reclaimRecentlyAllocatedNodes();
1251
1252 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1253 currStmt->getBeginLoc(),
1254 "Error evaluating statement");
1255
1256 // Remove dead bindings and symbols.
1257 ExplodedNodeSet CleanedStates;
1258 if (shouldRemoveDeadBindings(AMgr, S: currStmt, Pred, SF: Pred->getStackFrame())) {
1259 removeDead(Pred, Out&: CleanedStates, ReferenceStmt: currStmt, SF: Pred->getStackFrame());
1260 } else
1261 CleanedStates.insert(N: Pred);
1262
1263 ExplodedNodeSet PreVisited;
1264 if (shouldJustCallCheckers(S: currStmt, K: VisitKind::Pre)) {
1265 getCheckerManager().runCheckersForPreStmt(Dst&: PreVisited, Src: CleanedStates,
1266 S: currStmt, Eng&: *this);
1267 } else
1268 PreVisited.insert(S: CleanedStates);
1269
1270 ExplodedNodeSet Visited;
1271 for (const auto I : PreVisited) {
1272 ExplodedNodeSet Tmp;
1273 Visit(S: currStmt, Pred: I, Dst&: Tmp);
1274 Visited.insert(S: Tmp);
1275 }
1276
1277 ExplodedNodeSet PostVisited;
1278 if (shouldJustCallCheckers(S: currStmt, K: VisitKind::Post)) {
1279 getCheckerManager().runCheckersForPostStmt(Dst&: PostVisited, Src: Visited, S: currStmt,
1280 Eng&: *this);
1281 } else
1282 PostVisited.insert(S: Visited);
1283
1284 // Enqueue the new nodes onto the work list.
1285 Engine.enqueueStmtNodes(Set&: PostVisited, Block: getCurrBlock(), Idx: currStmtIdx);
1286}
1287
1288void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
1289 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1290 S->getBeginLoc(),
1291 "Error evaluating end of the loop");
1292 ProgramStateRef NewState = Pred->getState();
1293
1294 if(AMgr.options.ShouldUnrollLoops)
1295 NewState = processLoopEnd(LoopStmt: S, State: NewState);
1296
1297 LoopExit PP(S, Pred->getStackFrame());
1298 if (ExplodedNode *N = Engine.makeNode(Loc: PP, State: NewState, Pred))
1299 Engine.enqueueStmtNode(N, Block: getCurrBlock(), Idx: currStmtIdx);
1300}
1301
1302void ExprEngine::ProcessLifetimeEnd(const Stmt *S, const VarDecl *D,
1303 ExplodedNode *Pred) {
1304 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1305 S->getBeginLoc(),
1306 "Error evaluating end of a lifetime");
1307 LifetimeEnd PP(S, D, Pred->getStackFrame());
1308 ExplodedNode *Src = Engine.makeNode(Loc: PP, State: Pred->getState(), Pred);
1309
1310 ExplodedNodeSet Dst;
1311 getCheckerManager().runCheckersForLifetimeEnd(Dst, Src, Decl: D, Eng&: *this);
1312 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1313}
1314
1315void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
1316 ExplodedNode *Pred) {
1317 const CXXCtorInitializer *BMI = CFGInit.getInitializer();
1318 const Expr *Init = BMI->getInit()->IgnoreImplicit();
1319 const StackFrame *SF = Pred->getStackFrame();
1320
1321 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1322 BMI->getSourceLocation(),
1323 "Error evaluating initializer");
1324
1325 // We don't clean up dead bindings here.
1326 const auto *decl = cast<CXXConstructorDecl>(Val: SF->getDecl());
1327
1328 ProgramStateRef State = Pred->getState();
1329 SVal thisVal = State->getSVal(LV: svalBuilder.getCXXThis(D: decl, SF));
1330
1331 ExplodedNodeSet Tmp;
1332 SVal FieldLoc;
1333
1334 // Evaluate the initializer, if necessary
1335 if (BMI->isAnyMemberInitializer()) {
1336 // Constructors build the object directly in the field,
1337 // but non-objects must be copied in from the initializer.
1338 if (getObjectUnderConstruction(State, Item: BMI, SF)) {
1339 // The field was directly constructed, so there is no need to bind.
1340 // But we still need to stop tracking the object under construction.
1341 State = finishObjectConstruction(State, Item: BMI, SF);
1342 PostStore PS(Init, SF, /*Loc*/ nullptr, /*tag*/ nullptr);
1343 Tmp.insert(N: Engine.makeNode(Loc: PS, State, Pred));
1344 } else {
1345 const ValueDecl *Field;
1346 if (BMI->isIndirectMemberInitializer()) {
1347 Field = BMI->getIndirectMember();
1348 FieldLoc = State->getLValue(decl: BMI->getIndirectMember(), Base: thisVal);
1349 } else {
1350 Field = BMI->getMember();
1351 FieldLoc = State->getLValue(decl: BMI->getMember(), Base: thisVal);
1352 }
1353
1354 SVal InitVal;
1355 if (Field->getType()->isArrayType()) {
1356 // Handle arrays of trivial type. We can represent this with a
1357 // primitive load/copy from the base array region.
1358 const ArraySubscriptExpr *ASE;
1359 while ((ASE = dyn_cast<ArraySubscriptExpr>(Val: Init)))
1360 Init = ASE->getBase()->IgnoreImplicit();
1361
1362 InitVal = State->getSVal(E: Init, SF);
1363
1364 // If we fail to get the value for some reason, use a symbolic value.
1365 if (InitVal.isUnknownOrUndef()) {
1366 SValBuilder &SVB = getSValBuilder();
1367 InitVal = SVB.conjureSymbolVal(
1368 elem: getCFGElementRef(), SF, type: Field->getType(), visitCount: getNumVisitedCurrent());
1369 }
1370 } else {
1371 InitVal = State->getSVal(E: BMI->getInit(), SF);
1372 }
1373
1374 PostInitializer PP(BMI, FieldLoc.getAsRegion(), SF);
1375 evalBind(Dst&: Tmp, StoreE: Init, Pred, location: FieldLoc, Val: InitVal, /*isInit=*/AtDeclInit: true, PP: &PP);
1376 }
1377 } else if (BMI->isBaseInitializer() && isa<InitListExpr>(Val: Init)) {
1378 // When the base class is initialized with an initialization list and the
1379 // base class does not have a ctor, there will not be a CXXConstructExpr to
1380 // initialize the base region. Hence, we need to make the bind for it.
1381 SVal BaseLoc = getStoreManager().evalDerivedToBase(
1382 Derived: thisVal, DerivedPtrType: QualType(BMI->getBaseClass(), 0), IsVirtual: BMI->isBaseVirtual());
1383 SVal InitVal = State->getSVal(E: Init, SF);
1384 evalBind(Dst&: Tmp, StoreE: Init, Pred, location: BaseLoc, Val: InitVal, /*isInit=*/AtDeclInit: true);
1385 } else {
1386 assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
1387 Tmp.insert(N: Pred);
1388 // We already did all the work when visiting the CXXConstructExpr.
1389 }
1390
1391 // Construct PostInitializer nodes whether the state changed or not,
1392 // so that the diagnostics don't get confused.
1393 PostInitializer PP(BMI, FieldLoc.getAsRegion(), SF);
1394
1395 ExplodedNodeSet Dst;
1396 for (ExplodedNode *Pred : Tmp)
1397 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1398 // Enqueue the new nodes onto the work list.
1399 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1400}
1401
1402std::pair<ProgramStateRef, uint64_t>
1403ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State,
1404 const MemRegion *Region,
1405 const QualType &ElementTy,
1406 const StackFrame *SF,
1407 SVal *ElementCountVal) {
1408 assert(Region != nullptr && "Not-null region expected");
1409
1410 QualType Ty = ElementTy.getDesugaredType(Context: getContext());
1411 while (const auto *NTy = dyn_cast<ArrayType>(Val&: Ty))
1412 Ty = NTy->getElementType().getDesugaredType(Context: getContext());
1413
1414 auto ElementCount = getDynamicElementCount(State, MR: Region, SVB&: svalBuilder, Ty);
1415
1416 if (ElementCountVal)
1417 *ElementCountVal = ElementCount;
1418
1419 // Note: the destructors are called in reverse order.
1420 unsigned Idx = 0;
1421 if (auto OptionalIdx = getPendingArrayDestruction(State, SF)) {
1422 Idx = *OptionalIdx;
1423 } else {
1424 // The element count is either unknown, or an SVal that's not an integer.
1425 if (!ElementCount.isConstant())
1426 return {State, 0};
1427
1428 Idx = ElementCount.getAsInteger()->getLimitedValue();
1429 }
1430
1431 if (Idx == 0)
1432 return {State, 0};
1433
1434 --Idx;
1435
1436 return {setPendingArrayDestruction(State, SF, Idx), Idx};
1437}
1438
1439void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
1440 ExplodedNode *Pred) {
1441 ExplodedNodeSet Dst;
1442 switch (D.getKind()) {
1443 case CFGElement::AutomaticObjectDtor:
1444 ProcessAutomaticObjDtor(D: D.castAs<CFGAutomaticObjDtor>(), Pred, Dst);
1445 break;
1446 case CFGElement::BaseDtor:
1447 ProcessBaseDtor(D: D.castAs<CFGBaseDtor>(), Pred, Dst);
1448 break;
1449 case CFGElement::MemberDtor:
1450 ProcessMemberDtor(D: D.castAs<CFGMemberDtor>(), Pred, Dst);
1451 break;
1452 case CFGElement::TemporaryDtor:
1453 ProcessTemporaryDtor(D: D.castAs<CFGTemporaryDtor>(), Pred, Dst);
1454 break;
1455 case CFGElement::DeleteDtor:
1456 ProcessDeleteDtor(D: D.castAs<CFGDeleteDtor>(), Pred, Dst);
1457 break;
1458 default:
1459 llvm_unreachable("Unexpected dtor kind.");
1460 }
1461
1462 // Enqueue the new nodes onto the work list.
1463 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1464}
1465
1466void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
1467 ExplodedNode *Pred) {
1468 ExplodedNodeSet Dst;
1469 AnalysisManager &AMgr = getAnalysisManager();
1470 AnalyzerOptions &Opts = AMgr.options;
1471 // TODO: We're not evaluating allocators for all cases just yet as
1472 // we're not handling the return value correctly, which causes false
1473 // positives when the alpha.cplusplus.NewDeleteLeaks check is on.
1474 if (Opts.MayInlineCXXAllocator)
1475 VisitCXXNewAllocatorCall(CNE: NE, Pred, Dst);
1476 else {
1477 const StackFrame *SF = Pred->getStackFrame();
1478 PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), SF,
1479 getCFGElementRef());
1480 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1481 }
1482 Engine.enqueueStmtNodes(Set&: Dst, Block: getCurrBlock(), Idx: currStmtIdx);
1483}
1484
1485void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
1486 ExplodedNode *Pred,
1487 ExplodedNodeSet &Dst) {
1488 const auto *DtorDecl = Dtor.getDestructorDecl(astContext&: getContext());
1489 const VarDecl *varDecl = Dtor.getVarDecl();
1490 QualType varType = varDecl->getType();
1491
1492 ProgramStateRef state = Pred->getState();
1493 const StackFrame *SF = Pred->getStackFrame();
1494
1495 SVal dest = state->getLValue(VD: varDecl, SF);
1496 const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion();
1497
1498 if (varType->isReferenceType()) {
1499 const MemRegion *ValueRegion = state->getSVal(R: Region).getAsRegion();
1500 if (!ValueRegion) {
1501 // FIXME: This should not happen. The language guarantees a presence
1502 // of a valid initializer here, so the reference shall not be undefined.
1503 // It seems that we're calling destructors over variables that
1504 // were not initialized yet.
1505 return;
1506 }
1507 Region = ValueRegion->getBaseRegion();
1508 varType = cast<TypedValueRegion>(Val: Region)->getValueType();
1509 }
1510
1511 unsigned Idx = 0;
1512 if (isa<ArrayType>(Val: varType)) {
1513 SVal ElementCount;
1514 std::tie(args&: state, args&: Idx) = prepareStateForArrayDestruction(
1515 State: state, Region, ElementTy: varType, SF, ElementCountVal: &ElementCount);
1516
1517 if (ElementCount.isConstant()) {
1518 uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
1519 assert(ArrayLength &&
1520 "An automatic dtor for a 0 length array shouldn't be triggered!");
1521
1522 // Still handle this case if we don't have assertions enabled.
1523 if (!ArrayLength) {
1524 static SimpleProgramPointTag PT(
1525 "ExprEngine", "Skipping automatic 0 length array destruction, "
1526 "which shouldn't be in the CFG.");
1527 PostImplicitCall PP(DtorDecl, varDecl->getLocation(), SF,
1528 getCFGElementRef(), &PT);
1529 Engine.makeNode(Loc: PP, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
1530 return;
1531 }
1532 }
1533 }
1534
1535 EvalCallOptions CallOpts;
1536 Region = makeElementRegion(State: state, LValue: loc::MemRegionVal(Region), Ty&: varType,
1537 IsArray&: CallOpts.IsArrayCtorOrDtor, Idx)
1538 .getAsRegion();
1539
1540 static SimpleProgramPointTag PT("ExprEngine",
1541 "Prepare for object destruction");
1542 PreImplicitCall PP(DtorDecl, varDecl->getLocation(), SF, getCFGElementRef(),
1543 &PT);
1544 Pred = Engine.makeNode(Loc: PP, State: state, Pred);
1545
1546 if (!Pred)
1547 return;
1548
1549 VisitCXXDestructor(ObjectType: varType, Dest: Region, S: Dtor.getTriggerStmt(),
1550 /*IsBase=*/IsBaseDtor: false, Pred, Dst, Options&: CallOpts);
1551}
1552
1553void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
1554 ExplodedNode *Pred,
1555 ExplodedNodeSet &Dst) {
1556 ProgramStateRef State = Pred->getState();
1557 const StackFrame *SF = Pred->getStackFrame();
1558 const CXXDeleteExpr *DE = Dtor.getDeleteExpr();
1559 const Expr *Arg = DE->getArgument();
1560 QualType DTy = DE->getDestroyedType();
1561 SVal ArgVal = State->getSVal(E: Arg, SF);
1562
1563 // If the argument to delete is known to be a null value,
1564 // don't run destructor.
1565 if (State->isNull(V: ArgVal).isConstrainedTrue()) {
1566 QualType BTy = getContext().getBaseElementType(QT: DTy);
1567 const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl();
1568 const CXXDestructorDecl *Dtor = RD->getDestructor();
1569
1570 PostImplicitCall PP(Dtor, DE->getBeginLoc(), SF, getCFGElementRef());
1571 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1572 return;
1573 }
1574
1575 auto getDtorDecl = [](const QualType &DTy) {
1576 const CXXRecordDecl *RD = DTy->getAsCXXRecordDecl();
1577 return RD->getDestructor();
1578 };
1579
1580 unsigned Idx = 0;
1581 EvalCallOptions CallOpts;
1582 const MemRegion *ArgR = ArgVal.getAsRegion();
1583
1584 if (DE->isArrayForm()) {
1585 CallOpts.IsArrayCtorOrDtor = true;
1586 // Yes, it may even be a multi-dimensional array.
1587 while (const auto *AT = getContext().getAsArrayType(T: DTy))
1588 DTy = AT->getElementType();
1589
1590 if (ArgR) {
1591 SVal ElementCount;
1592 std::tie(args&: State, args&: Idx) =
1593 prepareStateForArrayDestruction(State, Region: ArgR, ElementTy: DTy, SF, ElementCountVal: &ElementCount);
1594
1595 // If we're about to destruct a 0 length array, don't run any of the
1596 // destructors.
1597 if (ElementCount.isConstant() &&
1598 ElementCount.getAsInteger()->getLimitedValue() == 0) {
1599
1600 static SimpleProgramPointTag PT(
1601 "ExprEngine", "Skipping 0 length array delete destruction");
1602 PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), SF,
1603 getCFGElementRef(), &PT);
1604 Dst.insert(N: Engine.makeNode(Loc: PP, State: Pred->getState(), Pred));
1605 return;
1606 }
1607
1608 ArgR = State->getLValue(ElementType: DTy, Idx: svalBuilder.makeArrayIndex(idx: Idx), Base: ArgVal)
1609 .getAsRegion();
1610 }
1611 }
1612
1613 static SimpleProgramPointTag PT("ExprEngine",
1614 "Prepare for object destruction");
1615 PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), SF,
1616 getCFGElementRef(), &PT);
1617 Pred = Engine.makeNode(Loc: PP, State, Pred);
1618
1619 if (!Pred)
1620 return;
1621
1622 VisitCXXDestructor(ObjectType: DTy, Dest: ArgR, S: DE, /*IsBase=*/IsBaseDtor: false, Pred, Dst, Options&: CallOpts);
1623}
1624
1625void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
1626 ExplodedNode *Pred, ExplodedNodeSet &Dst) {
1627 const StackFrame *SF = Pred->getStackFrame();
1628
1629 const auto *CurDtor = cast<CXXDestructorDecl>(Val: SF->getDecl());
1630 Loc ThisPtr = getSValBuilder().getCXXThis(D: CurDtor, SF);
1631 SVal ThisVal = Pred->getState()->getSVal(LV: ThisPtr);
1632
1633 // Create the base object region.
1634 const CXXBaseSpecifier *Base = D.getBaseSpecifier();
1635 QualType BaseTy = Base->getType();
1636 SVal BaseVal = getStoreManager().evalDerivedToBase(Derived: ThisVal, DerivedPtrType: BaseTy,
1637 IsVirtual: Base->isVirtual());
1638
1639 EvalCallOptions CallOpts;
1640 VisitCXXDestructor(ObjectType: BaseTy, Dest: BaseVal.getAsRegion(), S: CurDtor->getBody(),
1641 /*IsBase=*/IsBaseDtor: true, Pred, Dst, Options&: CallOpts);
1642}
1643
1644void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
1645 ExplodedNode *Pred, ExplodedNodeSet &Dst) {
1646 const auto *DtorDecl = D.getDestructorDecl(astContext&: getContext());
1647 const FieldDecl *Member = D.getFieldDecl();
1648 QualType T = Member->getType();
1649 ProgramStateRef State = Pred->getState();
1650 const StackFrame *SF = Pred->getStackFrame();
1651
1652 const auto *CurDtor = cast<CXXDestructorDecl>(Val: SF->getDecl());
1653 Loc ThisStorageLoc = getSValBuilder().getCXXThis(D: CurDtor, SF);
1654 Loc ThisLoc = State->getSVal(LV: ThisStorageLoc).castAs<Loc>();
1655 SVal FieldVal = State->getLValue(decl: Member, Base: ThisLoc);
1656
1657 unsigned Idx = 0;
1658 if (isa<ArrayType>(Val: T)) {
1659 SVal ElementCount;
1660 std::tie(args&: State, args&: Idx) = prepareStateForArrayDestruction(
1661 State, Region: FieldVal.getAsRegion(), ElementTy: T, SF, ElementCountVal: &ElementCount);
1662
1663 if (ElementCount.isConstant()) {
1664 uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
1665 assert(ArrayLength &&
1666 "A member dtor for a 0 length array shouldn't be triggered!");
1667
1668 // Still handle this case if we don't have assertions enabled.
1669 if (!ArrayLength) {
1670 static SimpleProgramPointTag PT(
1671 "ExprEngine", "Skipping member 0 length array destruction, which "
1672 "shouldn't be in the CFG.");
1673 PostImplicitCall PP(DtorDecl, Member->getLocation(), SF,
1674 getCFGElementRef(), &PT);
1675 Engine.makeNode(Loc: PP, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
1676 return;
1677 }
1678 }
1679 }
1680
1681 EvalCallOptions CallOpts;
1682 FieldVal =
1683 makeElementRegion(State, LValue: FieldVal, Ty&: T, IsArray&: CallOpts.IsArrayCtorOrDtor, Idx);
1684
1685 static SimpleProgramPointTag PT("ExprEngine",
1686 "Prepare for object destruction");
1687 PreImplicitCall PP(DtorDecl, Member->getLocation(), SF, getCFGElementRef(),
1688 &PT);
1689 Pred = Engine.makeNode(Loc: PP, State, Pred);
1690
1691 if (!Pred)
1692 return;
1693
1694 VisitCXXDestructor(ObjectType: T, Dest: FieldVal.getAsRegion(), S: CurDtor->getBody(),
1695 /*IsBase=*/IsBaseDtor: false, Pred, Dst, Options&: CallOpts);
1696}
1697
1698void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
1699 ExplodedNode *Pred,
1700 ExplodedNodeSet &Dst) {
1701 const CXXBindTemporaryExpr *BTE = D.getBindTemporaryExpr();
1702 ProgramStateRef State = Pred->getState();
1703 const StackFrame *SF = Pred->getStackFrame();
1704 const MemRegion *MR = nullptr;
1705
1706 if (std::optional<SVal> V = getObjectUnderConstruction(State, Item: BTE, SF)) {
1707 // FIXME: Currently we insert temporary destructors for default parameters,
1708 // but we don't insert the constructors, so the entry in
1709 // ObjectsUnderConstruction may be missing.
1710 State = finishObjectConstruction(State, Item: BTE, SF);
1711 MR = V->getAsRegion();
1712 }
1713
1714 // If copy elision has occurred, and the constructor corresponding to the
1715 // destructor was elided, we need to skip the destructor as well.
1716 if (isDestructorElided(State, BTE, SF)) {
1717 State = cleanupElidedDestructor(State, BTE, SF);
1718 PostImplicitCall PP(D.getDestructorDecl(astContext&: getContext()), BTE->getBeginLoc(),
1719 SF, getCFGElementRef());
1720 Dst.insert(N: Engine.makeNode(Loc: PP, State, Pred));
1721 return;
1722 }
1723
1724 ExplodedNode *CleanPred = Engine.makePostStmtNode(S: BTE, State, Pred);
1725 if (!CleanPred) {
1726 // FIXME: We can get a null node here due to temporaries being
1727 // bound to default parameters.
1728 CleanPred = Pred;
1729 }
1730
1731 QualType T = BTE->getSubExpr()->getType();
1732
1733 EvalCallOptions CallOpts;
1734 CallOpts.IsTemporaryCtorOrDtor = true;
1735 if (!MR) {
1736 // FIXME: If we have no MR, we still need to unwrap the array to avoid
1737 // destroying the whole array at once.
1738 //
1739 // For this case there is no universal solution as there is no way to
1740 // directly create an array of temporary objects. There are some expressions
1741 // however which can create temporary objects and have an array type.
1742 //
1743 // E.g.: std::initializer_list<S>{S(), S()};
1744 //
1745 // The expression above has a type of 'const struct S[2]' but it's a single
1746 // 'std::initializer_list<>'. The destructors of the 2 temporary 'S()'
1747 // objects will be called anyway, because they are 2 separate objects in 2
1748 // separate clusters, i.e.: not an array.
1749 //
1750 // Now the 'std::initializer_list<>' is not an array either even though it
1751 // has the type of an array. The point is, we only want to invoke the
1752 // destructor for the initializer list once not twice or so.
1753 while (const ArrayType *AT = getContext().getAsArrayType(T)) {
1754 T = AT->getElementType();
1755
1756 // FIXME: Enable this flag once we handle this case properly.
1757 // CallOpts.IsArrayCtorOrDtor = true;
1758 }
1759 } else {
1760 // FIXME: We'd eventually need to makeElementRegion() trick here,
1761 // but for now we don't have the respective construction contexts,
1762 // so MR would always be null in this case. Do nothing for now.
1763 }
1764 VisitCXXDestructor(ObjectType: T, Dest: MR, S: BTE,
1765 /*IsBase=*/IsBaseDtor: false, Pred: CleanPred, Dst, Options&: CallOpts);
1766}
1767
1768void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
1769 ExplodedNode *Pred,
1770 ExplodedNodeSet &Dst,
1771 const CFGBlock *DstT,
1772 const CFGBlock *DstF) {
1773 ProgramStateRef State = Pred->getState();
1774 const StackFrame *SF = Pred->getStackFrame();
1775
1776 std::optional<SVal> Obj = getObjectUnderConstruction(State, Item: BTE, SF);
1777 if (const CFGBlock *DstBlock = Obj ? DstT : DstF) {
1778 BlockEdge BE(getCurrBlock(), DstBlock, SF);
1779 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred));
1780 }
1781}
1782
1783void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
1784 ExplodedNode *Pred,
1785 ExplodedNodeSet &Dst) {
1786 // This is a fallback solution in case we didn't have a construction
1787 // context when we were constructing the temporary. Otherwise the map should
1788 // have been populated there.
1789 if (!getAnalysisManager().options.ShouldIncludeTemporaryDtorsInCFG) {
1790 // In case we don't have temporary destructors in the CFG, do not mark
1791 // the initialization - we would otherwise never clean it up.
1792 Dst.insert(N: Pred);
1793 return;
1794 }
1795 ProgramStateRef State = Pred->getState();
1796 const StackFrame *SF = Pred->getStackFrame();
1797 if (!getObjectUnderConstruction(State, Item: BTE, SF)) {
1798 // FIXME: Currently the state might also already contain the marker due to
1799 // incorrect handling of temporaries bound to default parameters; for
1800 // those, we currently skip the CXXBindTemporaryExpr but rely on adding
1801 // temporary destructor nodes.
1802 State = addObjectUnderConstruction(State, Item: BTE, SF, V: UnknownVal());
1803 }
1804 Dst.insert(N: Engine.makePostStmtNode(S: BTE, State, Pred));
1805}
1806
1807ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State,
1808 ArrayRef<SVal> Vs,
1809 PointerEscapeKind K,
1810 const CallEvent *Call) const {
1811 class CollectReachableSymbolsCallback final : public SymbolVisitor {
1812 InvalidatedSymbols &Symbols;
1813
1814 public:
1815 explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols)
1816 : Symbols(Symbols) {}
1817
1818 const InvalidatedSymbols &getSymbols() const { return Symbols; }
1819
1820 bool VisitSymbol(SymbolRef Sym) override {
1821 Symbols.insert(V: Sym);
1822 return true;
1823 }
1824 };
1825 InvalidatedSymbols Symbols;
1826 CollectReachableSymbolsCallback CallBack(Symbols);
1827 for (SVal V : Vs)
1828 State->scanReachableSymbols(val: V, visitor&: CallBack);
1829
1830 return getCheckerManager().runCheckersForPointerEscape(
1831 State, Escaped: CallBack.getSymbols(), Call, Kind: K, ITraits: nullptr);
1832}
1833
1834void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
1835 ExplodedNodeSet &Dst) {
1836 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
1837 S->getBeginLoc(), "Error evaluating statement");
1838
1839 assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens());
1840
1841 switch (S->getStmtClass()) {
1842 // C++, OpenMP and ARC stuff we don't support yet.
1843 case Stmt::CXXDependentScopeMemberExprClass:
1844 case Stmt::CXXReflectExprClass:
1845 case Stmt::CXXTryStmtClass:
1846 case Stmt::CXXTypeidExprClass:
1847 case Stmt::CXXUuidofExprClass:
1848 case Stmt::CXXFoldExprClass:
1849 case Stmt::MSPropertyRefExprClass:
1850 case Stmt::MSPropertySubscriptExprClass:
1851 case Stmt::CXXUnresolvedConstructExprClass:
1852 case Stmt::DependentScopeDeclRefExprClass:
1853 case Stmt::ArrayTypeTraitExprClass:
1854 case Stmt::ExpressionTraitExprClass:
1855 case Stmt::UnresolvedLookupExprClass:
1856 case Stmt::UnresolvedMemberExprClass:
1857 case Stmt::DependentTemplateIdExprClass:
1858 case Stmt::RecoveryExprClass:
1859 case Stmt::CXXNoexceptExprClass:
1860 case Stmt::PackExpansionExprClass:
1861 case Stmt::PackIndexingExprClass:
1862 case Stmt::SubstNonTypeTemplateParmPackExprClass:
1863 case Stmt::FunctionParmPackExprClass:
1864 case Stmt::CoroutineBodyStmtClass:
1865 case Stmt::CoawaitExprClass:
1866 case Stmt::DependentCoawaitExprClass:
1867 case Stmt::CoreturnStmtClass:
1868 case Stmt::CoyieldExprClass:
1869 case Stmt::SEHTryStmtClass:
1870 case Stmt::SEHExceptStmtClass:
1871 case Stmt::SEHLeaveStmtClass:
1872 case Stmt::SEHFinallyStmtClass:
1873 case Stmt::CXXExpansionStmtPatternClass:
1874 case Stmt::CXXExpansionStmtInstantiationClass:
1875 case Stmt::CXXExpansionSelectExprClass:
1876 case Stmt::OMPCanonicalLoopClass:
1877 case Stmt::OMPParallelDirectiveClass:
1878 case Stmt::OMPSimdDirectiveClass:
1879 case Stmt::OMPForDirectiveClass:
1880 case Stmt::OMPForSimdDirectiveClass:
1881 case Stmt::OMPSectionsDirectiveClass:
1882 case Stmt::OMPSectionDirectiveClass:
1883 case Stmt::OMPScopeDirectiveClass:
1884 case Stmt::OMPSingleDirectiveClass:
1885 case Stmt::OMPMasterDirectiveClass:
1886 case Stmt::OMPCriticalDirectiveClass:
1887 case Stmt::OMPParallelForDirectiveClass:
1888 case Stmt::OMPParallelForSimdDirectiveClass:
1889 case Stmt::OMPParallelSectionsDirectiveClass:
1890 case Stmt::OMPParallelMasterDirectiveClass:
1891 case Stmt::OMPParallelMaskedDirectiveClass:
1892 case Stmt::OMPTaskDirectiveClass:
1893 case Stmt::OMPTaskyieldDirectiveClass:
1894 case Stmt::OMPBarrierDirectiveClass:
1895 case Stmt::OMPTaskwaitDirectiveClass:
1896 case Stmt::OMPErrorDirectiveClass:
1897 case Stmt::OMPTaskgroupDirectiveClass:
1898 case Stmt::OMPFlushDirectiveClass:
1899 case Stmt::OMPDepobjDirectiveClass:
1900 case Stmt::OMPScanDirectiveClass:
1901 case Stmt::OMPOrderedStandaloneDirectiveClass:
1902 case Stmt::OMPOrderedBlockAssocDirectiveClass:
1903 case Stmt::OMPAtomicDirectiveClass:
1904 case Stmt::OMPAssumeDirectiveClass:
1905 case Stmt::OMPTargetDirectiveClass:
1906 case Stmt::OMPTargetDataDirectiveClass:
1907 case Stmt::OMPTargetEnterDataDirectiveClass:
1908 case Stmt::OMPTargetExitDataDirectiveClass:
1909 case Stmt::OMPTargetParallelDirectiveClass:
1910 case Stmt::OMPTargetParallelForDirectiveClass:
1911 case Stmt::OMPTargetUpdateDirectiveClass:
1912 case Stmt::OMPTeamsDirectiveClass:
1913 case Stmt::OMPCancellationPointDirectiveClass:
1914 case Stmt::OMPCancelDirectiveClass:
1915 case Stmt::OMPTaskLoopDirectiveClass:
1916 case Stmt::OMPTaskLoopSimdDirectiveClass:
1917 case Stmt::OMPMasterTaskLoopDirectiveClass:
1918 case Stmt::OMPMaskedTaskLoopDirectiveClass:
1919 case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
1920 case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
1921 case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
1922 case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
1923 case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
1924 case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
1925 case Stmt::OMPDistributeDirectiveClass:
1926 case Stmt::OMPDistributeParallelForDirectiveClass:
1927 case Stmt::OMPDistributeParallelForSimdDirectiveClass:
1928 case Stmt::OMPDistributeSimdDirectiveClass:
1929 case Stmt::OMPTargetParallelForSimdDirectiveClass:
1930 case Stmt::OMPTargetSimdDirectiveClass:
1931 case Stmt::OMPTeamsDistributeDirectiveClass:
1932 case Stmt::OMPTeamsDistributeSimdDirectiveClass:
1933 case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
1934 case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
1935 case Stmt::OMPTargetTeamsDirectiveClass:
1936 case Stmt::OMPTargetTeamsDistributeDirectiveClass:
1937 case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
1938 case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
1939 case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
1940 case Stmt::OMPReverseDirectiveClass:
1941 case Stmt::OMPStripeDirectiveClass:
1942 case Stmt::OMPTileDirectiveClass:
1943 case Stmt::OMPInterchangeDirectiveClass:
1944 case Stmt::OMPFlattenDirectiveClass:
1945 case Stmt::OMPSplitDirectiveClass:
1946 case Stmt::OMPFuseDirectiveClass:
1947 case Stmt::OMPInteropDirectiveClass:
1948 case Stmt::OMPDispatchDirectiveClass:
1949 case Stmt::OMPMaskedDirectiveClass:
1950 case Stmt::OMPGenericLoopDirectiveClass:
1951 case Stmt::OMPTeamsGenericLoopDirectiveClass:
1952 case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
1953 case Stmt::OMPParallelGenericLoopDirectiveClass:
1954 case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
1955 case Stmt::CapturedStmtClass:
1956 case Stmt::SYCLKernelCallStmtClass:
1957 case Stmt::UnresolvedSYCLKernelCallStmtClass:
1958 case Stmt::OpenACCComputeConstructClass:
1959 case Stmt::OpenACCLoopConstructClass:
1960 case Stmt::OpenACCCombinedConstructClass:
1961 case Stmt::OpenACCDataConstructClass:
1962 case Stmt::OpenACCEnterDataConstructClass:
1963 case Stmt::OpenACCExitDataConstructClass:
1964 case Stmt::OpenACCHostDataConstructClass:
1965 case Stmt::OpenACCWaitConstructClass:
1966 case Stmt::OpenACCCacheConstructClass:
1967 case Stmt::OpenACCInitConstructClass:
1968 case Stmt::OpenACCShutdownConstructClass:
1969 case Stmt::OpenACCSetConstructClass:
1970 case Stmt::OpenACCUpdateConstructClass:
1971 case Stmt::OpenACCAtomicConstructClass:
1972 case Stmt::OMPUnrollDirectiveClass:
1973 case Stmt::OMPMetaDirectiveClass:
1974 case Stmt::HLSLOutArgExprClass: {
1975 const ExplodedNode *Node = Engine.makePostStmtNode(
1976 S, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
1977 Engine.addAbortedBlock(node: Node, block: getCurrBlock());
1978 break;
1979 }
1980
1981 case Stmt::ParenExprClass:
1982 llvm_unreachable("ParenExprs already handled.");
1983 case Stmt::GenericSelectionExprClass:
1984 llvm_unreachable("GenericSelectionExprs already handled.");
1985 // Cases that should never be evaluated simply because they shouldn't
1986 // appear in the CFG.
1987 case Stmt::BreakStmtClass:
1988 case Stmt::CaseStmtClass:
1989 case Stmt::CompoundStmtClass:
1990 case Stmt::ContinueStmtClass:
1991 case Stmt::CXXForRangeStmtClass:
1992 case Stmt::DefaultStmtClass:
1993 case Stmt::DoStmtClass:
1994 case Stmt::ForStmtClass:
1995 case Stmt::GotoStmtClass:
1996 case Stmt::IfStmtClass:
1997 case Stmt::IndirectGotoStmtClass:
1998 case Stmt::LabelStmtClass:
1999 case Stmt::NoStmtClass:
2000 case Stmt::NullStmtClass:
2001 case Stmt::SwitchStmtClass:
2002 case Stmt::WhileStmtClass:
2003 case Stmt::DeferStmtClass:
2004 case Expr::MSDependentExistsStmtClass:
2005 llvm_unreachable("Stmt should not be in analyzer evaluation loop");
2006 case Stmt::ImplicitValueInitExprClass:
2007 // These nodes are shared in the CFG and would case caching out.
2008 // Moreover, no additional evaluation required for them, the
2009 // analyzer can reconstruct these values from the AST.
2010 llvm_unreachable("Should be pruned from CFG");
2011
2012 case Stmt::ObjCSubscriptRefExprClass:
2013 case Stmt::ObjCPropertyRefExprClass:
2014 llvm_unreachable("These are handled by PseudoObjectExpr");
2015
2016 case Stmt::GNUNullExprClass: {
2017 // GNU __null is a pointer-width integer, not an actual pointer.
2018 SVal Val = svalBuilder.makeIntValWithWidth(ptrType: getContext().VoidPtrTy, integer: 0);
2019 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: cast<Expr>(Val: S), V: Val));
2020 break;
2021 }
2022
2023 case Stmt::ObjCAtSynchronizedStmtClass: {
2024 Dst.insert(N: Pred);
2025 break;
2026 }
2027
2028 case Expr::ConstantExprClass:
2029 case Stmt::ExprWithCleanupsClass:
2030 Dst.insert(N: Pred);
2031 // Handled due to fully linearised CFG.
2032 break;
2033
2034 case Stmt::CXXBindTemporaryExprClass:
2035 VisitCXXBindTemporaryExpr(BTE: cast<CXXBindTemporaryExpr>(Val: S), Pred, Dst);
2036 break;
2037
2038 case Stmt::ArrayInitLoopExprClass:
2039 VisitArrayInitLoopExpr(Ex: cast<ArrayInitLoopExpr>(Val: S), Pred, Dst);
2040 break;
2041 // Cases not handled yet; but will handle some day.
2042 case Stmt::DesignatedInitExprClass:
2043 case Stmt::DesignatedInitUpdateExprClass:
2044 case Stmt::ArrayInitIndexExprClass:
2045 case Stmt::ExtVectorElementExprClass:
2046 case Stmt::MatrixElementExprClass:
2047 case Stmt::ImaginaryLiteralClass:
2048 case Stmt::ObjCAtCatchStmtClass:
2049 case Stmt::ObjCAtFinallyStmtClass:
2050 case Stmt::ObjCAtTryStmtClass:
2051 case Stmt::ObjCAutoreleasePoolStmtClass:
2052 case Stmt::ObjCEncodeExprClass:
2053 case Stmt::ObjCIsaExprClass:
2054 case Stmt::ObjCProtocolExprClass:
2055 case Stmt::ObjCSelectorExprClass:
2056 case Stmt::ParenListExprClass:
2057 case Stmt::ShuffleVectorExprClass:
2058 case Stmt::ConvertVectorExprClass:
2059 case Stmt::VAArgExprClass:
2060 case Stmt::CUDAKernelCallExprClass:
2061 case Stmt::OpaqueValueExprClass:
2062 case Stmt::AsTypeExprClass:
2063 case Stmt::ConceptSpecializationExprClass:
2064 case Stmt::CXXRewrittenBinaryOperatorClass:
2065 case Stmt::RequiresExprClass:
2066 case Stmt::EmbedExprClass:
2067 // Fall through.
2068
2069 // Cases we intentionally don't evaluate, since they don't need
2070 // to be explicitly evaluated.
2071 case Stmt::PredefinedExprClass:
2072 case Stmt::AddrLabelExprClass:
2073 case Stmt::IntegerLiteralClass:
2074 case Stmt::FixedPointLiteralClass:
2075 case Stmt::CharacterLiteralClass:
2076 case Stmt::CXXScalarValueInitExprClass:
2077 case Stmt::CXXBoolLiteralExprClass:
2078 case Stmt::ObjCBoolLiteralExprClass:
2079 case Stmt::ObjCAvailabilityCheckExprClass:
2080 case Stmt::FloatingLiteralClass:
2081 case Stmt::NoInitExprClass:
2082 case Stmt::SizeOfPackExprClass:
2083 case Stmt::StringLiteralClass:
2084 case Stmt::SourceLocExprClass:
2085 case Stmt::ObjCStringLiteralClass:
2086 case Stmt::CXXPseudoDestructorExprClass:
2087 case Stmt::SubstNonTypeTemplateParmExprClass:
2088 case Stmt::CXXNullPtrLiteralExprClass:
2089 case Stmt::ArraySectionExprClass:
2090 case Stmt::OMPArrayShapingExprClass:
2091 case Stmt::OMPIteratorExprClass:
2092 case Stmt::SYCLUniqueStableNameExprClass:
2093 case Stmt::OpenACCAsteriskSizeExprClass:
2094 case Stmt::TypeTraitExprClass: {
2095 Dst.insert(N: Pred);
2096 break;
2097 }
2098
2099 case Stmt::AttributedStmtClass:
2100 VisitAttributedStmt(A: cast<AttributedStmt>(Val: S), Pred, Dst);
2101 break;
2102
2103 case Stmt::CXXDefaultArgExprClass:
2104 case Stmt::CXXDefaultInitExprClass: {
2105
2106 const Expr *ArgE;
2107 if (const auto *DefE = dyn_cast<CXXDefaultArgExpr>(Val: S))
2108 ArgE = DefE->getExpr();
2109 else if (const auto *DefE = dyn_cast<CXXDefaultInitExpr>(Val: S))
2110 ArgE = DefE->getExpr();
2111 else
2112 llvm_unreachable("unknown constant wrapper kind");
2113
2114 bool IsTemporary = false;
2115 if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Val: ArgE)) {
2116 ArgE = MTE->getSubExpr();
2117 IsTemporary = true;
2118 }
2119
2120 std::optional<SVal> ConstantVal = svalBuilder.getConstantVal(E: ArgE);
2121 if (!ConstantVal)
2122 ConstantVal = UnknownVal();
2123
2124 const StackFrame *SF = Pred->getStackFrame();
2125 ProgramStateRef State = Pred->getState();
2126 State = State->BindExpr(E: cast<Expr>(Val: S), SF, V: *ConstantVal);
2127 if (IsTemporary)
2128 State = createTemporaryRegionIfNeeded(State, SF, InitWithAdjustments: cast<Expr>(Val: S),
2129 Result: cast<Expr>(Val: S));
2130 Dst.insert(N: Engine.makePostStmtNode(S, State, Pred));
2131
2132 break;
2133 }
2134
2135 // Cases we evaluate as opaque expressions, conjuring a symbol.
2136 case Stmt::CXXStdInitializerListExprClass:
2137 case Expr::ObjCArrayLiteralClass:
2138 case Expr::ObjCDictionaryLiteralClass:
2139 case Expr::ObjCBoxedExprClass: {
2140 const auto *Ex = cast<Expr>(Val: S);
2141 QualType resultType = Ex->getType();
2142
2143 const StackFrame *SF = Pred->getStackFrame();
2144 SVal result = svalBuilder.conjureSymbolVal(
2145 /*symbolTag=*/nullptr, elem: getCFGElementRef(), SF, type: resultType,
2146 count: getNumVisitedCurrent());
2147 ProgramStateRef State = Pred->getState()->BindExpr(E: Ex, SF, V: result);
2148
2149 // Escape pointers passed into the list, unless it's an ObjC boxed
2150 // expression which is not a boxable C structure.
2151 if (!(isa<ObjCBoxedExpr>(Val: Ex) &&
2152 !cast<ObjCBoxedExpr>(Val: Ex)->getSubExpr()->getType()->isRecordType()))
2153 for (auto Child : Ex->children()) {
2154 assert(Child);
2155 const auto *ChildExpr = dyn_cast<Expr>(Val: Child);
2156 SVal Val = ChildExpr ? State->getSVal(E: ChildExpr, SF) : UnknownVal();
2157 State = escapeValues(State, Vs: Val, K: PSK_EscapeOther);
2158 }
2159
2160 Dst.insert(N: Engine.makePostStmtNode(S, State, Pred));
2161 break;
2162 }
2163
2164 case Stmt::ArraySubscriptExprClass:
2165 VisitArraySubscriptExpr(Ex: cast<ArraySubscriptExpr>(Val: S), Pred, Dst);
2166 break;
2167
2168 case Stmt::MatrixSingleSubscriptExprClass:
2169 llvm_unreachable(
2170 "Support for MatrixSingleSubscriptExprClass is not implemented.");
2171 break;
2172
2173 case Stmt::MatrixSubscriptExprClass:
2174 llvm_unreachable("Support for MatrixSubscriptExpr is not implemented.");
2175 break;
2176
2177 case Stmt::GCCAsmStmtClass:
2178 VisitGCCAsmStmt(A: cast<GCCAsmStmt>(Val: S), Pred, Dst);
2179 break;
2180
2181 case Stmt::MSAsmStmtClass:
2182 VisitMSAsmStmt(A: cast<MSAsmStmt>(Val: S), Pred, Dst);
2183 break;
2184
2185 case Stmt::BlockExprClass:
2186 VisitBlockExpr(BE: cast<BlockExpr>(Val: S), Pred, Dst);
2187 break;
2188
2189 case Stmt::LambdaExprClass:
2190 VisitLambdaExpr(LE: cast<LambdaExpr>(Val: S), Pred, Dst);
2191 break;
2192
2193 case Stmt::BinaryOperatorClass: {
2194 const auto *B = cast<BinaryOperator>(Val: S);
2195 if (B->isLogicalOp()) {
2196 VisitLogicalExpr(B, Pred, Dst);
2197 break;
2198 } else if (B->getOpcode() == BO_Comma) {
2199 SVal Val =
2200 Pred->getState()->getSVal(E: B->getRHS(), SF: Pred->getStackFrame());
2201 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: B, V: Val));
2202 break;
2203 }
2204
2205 if (AMgr.options.ShouldEagerlyAssume &&
2206 (B->isRelationalOp() || B->isEqualityOp())) {
2207 ExplodedNodeSet Tmp;
2208 VisitBinaryOperator(B: cast<BinaryOperator>(Val: S), Pred, Dst&: Tmp);
2209 evalEagerlyAssumeBifurcation(Dst, Src&: Tmp, Ex: cast<Expr>(Val: S));
2210 }
2211 else
2212 VisitBinaryOperator(B: cast<BinaryOperator>(Val: S), Pred, Dst);
2213
2214 break;
2215 }
2216
2217 case Stmt::CXXOperatorCallExprClass:
2218 case Stmt::CallExprClass:
2219 case Stmt::CXXMemberCallExprClass:
2220 case Stmt::UserDefinedLiteralClass:
2221 VisitCallExpr(CE: cast<CallExpr>(Val: S), Pred, Dst);
2222 break;
2223
2224 case Stmt::CXXCatchStmtClass:
2225 VisitCXXCatchStmt(CS: cast<CXXCatchStmt>(Val: S), Pred, Dst);
2226 break;
2227
2228 case Stmt::CXXTemporaryObjectExprClass:
2229 case Stmt::CXXConstructExprClass:
2230 VisitCXXConstructExpr(E: cast<CXXConstructExpr>(Val: S), Pred, Dst);
2231 break;
2232
2233 case Stmt::CXXInheritedCtorInitExprClass:
2234 VisitCXXInheritedCtorInitExpr(E: cast<CXXInheritedCtorInitExpr>(Val: S), Pred,
2235 Dst);
2236 break;
2237
2238 case Stmt::CXXNewExprClass:
2239 VisitCXXNewExpr(CNE: cast<CXXNewExpr>(Val: S), Pred, Dst);
2240 break;
2241
2242 case Stmt::CXXDeleteExprClass:
2243 VisitCXXDeleteExpr(CDE: cast<CXXDeleteExpr>(Val: S), Pred, Dst);
2244 break;
2245
2246 // FIXME: ChooseExpr is really a constant. We need to fix
2247 // the CFG do not model them as explicit control-flow.
2248 case Stmt::ChooseExprClass: { // __builtin_choose_expr
2249 const auto *C = cast<ChooseExpr>(Val: S);
2250 VisitGuardedExpr(Ex: C, L: C->getLHS(), R: C->getRHS(), Pred, Dst);
2251 break;
2252 }
2253
2254 case Stmt::CompoundAssignOperatorClass:
2255 VisitBinaryOperator(B: cast<BinaryOperator>(Val: S), Pred, Dst);
2256 break;
2257
2258 case Stmt::CompoundLiteralExprClass:
2259 VisitCompoundLiteralExpr(CL: cast<CompoundLiteralExpr>(Val: S), Pred, Dst);
2260 break;
2261
2262 case Stmt::BinaryConditionalOperatorClass:
2263 case Stmt::ConditionalOperatorClass: { // '?' operator
2264 const auto *C = cast<AbstractConditionalOperator>(Val: S);
2265 VisitGuardedExpr(Ex: C, L: C->getTrueExpr(), R: C->getFalseExpr(), Pred, Dst);
2266 break;
2267 }
2268
2269 case Stmt::CXXThisExprClass:
2270 VisitCXXThisExpr(TE: cast<CXXThisExpr>(Val: S), Pred, Dst);
2271 break;
2272
2273 case Stmt::DeclRefExprClass: {
2274 const auto *DE = cast<DeclRefExpr>(Val: S);
2275 VisitCommonDeclRefExpr(DR: DE, D: DE->getDecl(), Pred, Dst);
2276 break;
2277 }
2278
2279 case Stmt::DeclStmtClass:
2280 VisitDeclStmt(DS: cast<DeclStmt>(Val: S), Pred, Dst);
2281 break;
2282
2283 case Stmt::ImplicitCastExprClass:
2284 case Stmt::CStyleCastExprClass:
2285 case Stmt::CXXStaticCastExprClass:
2286 case Stmt::CXXDynamicCastExprClass:
2287 case Stmt::CXXReinterpretCastExprClass:
2288 case Stmt::CXXConstCastExprClass:
2289 case Stmt::CXXFunctionalCastExprClass:
2290 case Stmt::BuiltinBitCastExprClass:
2291 case Stmt::ObjCBridgedCastExprClass:
2292 case Stmt::CXXAddrspaceCastExprClass:
2293 VisitCastExpr(CastE: cast<CastExpr>(Val: S), Pred, Dst);
2294 break;
2295
2296 case Expr::MaterializeTemporaryExprClass:
2297 VisitMaterializeTemporaryExpr(MTE: cast<MaterializeTemporaryExpr>(Val: S), Pred,
2298 Dst);
2299 break;
2300
2301 case Stmt::InitListExprClass: {
2302 const InitListExpr *E = cast<InitListExpr>(Val: S);
2303 ConstructInitList(Source: E, Args: E->inits(), IsTransparent: E->isTransparent(), Pred, Dst);
2304 break;
2305 }
2306
2307 case Expr::CXXParenListInitExprClass:
2308 VisitCXXParenListInitExpr(E: cast<CXXParenListInitExpr>(Val: S), Pred, Dst);
2309 break;
2310
2311 case Stmt::MemberExprClass:
2312 VisitMemberExpr(M: cast<MemberExpr>(Val: S), Pred, Dst);
2313 break;
2314
2315 case Stmt::AtomicExprClass:
2316 VisitAtomicExpr(E: cast<AtomicExpr>(Val: S), Pred, Dst);
2317 break;
2318
2319 case Stmt::ObjCIvarRefExprClass:
2320 VisitLvalObjCIvarRefExpr(DR: cast<ObjCIvarRefExpr>(Val: S), Pred, Dst);
2321 break;
2322
2323 case Stmt::ObjCForCollectionStmtClass:
2324 VisitObjCForCollectionStmt(S: cast<ObjCForCollectionStmt>(Val: S), Pred, Dst);
2325 break;
2326
2327 case Stmt::ObjCMessageExprClass:
2328 VisitObjCMessage(ME: cast<ObjCMessageExpr>(Val: S), Pred, Dst);
2329 break;
2330
2331 case Stmt::ObjCAtThrowStmtClass:
2332 case Stmt::CXXThrowExprClass:
2333 // FIXME: This is not complete. We basically treat @throw as
2334 // an abort.
2335 Engine.makePostStmtNode(S, State: Pred->getState(), Pred, /*MarkAsSink=*/true);
2336 break;
2337
2338 case Stmt::ReturnStmtClass:
2339 VisitReturnStmt(R: cast<ReturnStmt>(Val: S), Pred, Dst);
2340 break;
2341
2342 case Stmt::OffsetOfExprClass:
2343 VisitOffsetOfExpr(Ex: cast<OffsetOfExpr>(Val: S), Pred, Dst);
2344 break;
2345
2346 case Stmt::UnaryExprOrTypeTraitExprClass:
2347 VisitUnaryExprOrTypeTraitExpr(Ex: cast<UnaryExprOrTypeTraitExpr>(Val: S), Pred,
2348 Dst);
2349 break;
2350
2351 case Stmt::StmtExprClass:
2352 VisitStmtExpr(SE: cast<StmtExpr>(Val: S), Pred, Dst);
2353 break;
2354
2355 case Stmt::UnaryOperatorClass: {
2356 const auto *U = cast<UnaryOperator>(Val: S);
2357 if (AMgr.options.ShouldEagerlyAssume && (U->getOpcode() == UO_LNot)) {
2358 ExplodedNodeSet Tmp;
2359 VisitUnaryOperator(B: U, Pred, Dst&: Tmp);
2360 evalEagerlyAssumeBifurcation(Dst, Src&: Tmp, Ex: U);
2361 }
2362 else
2363 VisitUnaryOperator(B: U, Pred, Dst);
2364 break;
2365 }
2366
2367 case Stmt::PseudoObjectExprClass:
2368 VisitPseudoObjectExpr(PE: cast<PseudoObjectExpr>(Val: S), Pred, Dst);
2369 break;
2370
2371 case Expr::ObjCIndirectCopyRestoreExprClass:
2372 VisitObjCIndirectCopyRestoreExpr(OIE: cast<ObjCIndirectCopyRestoreExpr>(Val: S),
2373 Pred, Dst);
2374 break;
2375 }
2376}
2377
2378bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
2379 const StackFrame *CalleeSF) {
2380 const StackFrame *CallerSF = CalleeSF->getParent();
2381 assert(CalleeSF && CallerSF);
2382 ExplodedNode *BeforeProcessingCall = nullptr;
2383 const Expr *CE = CalleeSF->getCallSite();
2384
2385 // Find the first node before we started processing the call expression.
2386 while (N) {
2387 ProgramPoint L = N->getLocation();
2388 BeforeProcessingCall = N;
2389 N = N->pred_empty() ? nullptr : *(N->pred_begin());
2390
2391 // Skip the nodes corresponding to the inlined code.
2392 if (L.getStackFrame() != CallerSF)
2393 continue;
2394 // We reached the caller. Find the node right before we started
2395 // processing the call.
2396 if (L.isPurgeKind())
2397 continue;
2398 if (L.getAs<PreImplicitCall>())
2399 continue;
2400 if (L.getAs<CallEnter>())
2401 continue;
2402 if (std::optional<StmtPoint> SP = L.getAs<StmtPoint>())
2403 if (SP->getStmt() == CE)
2404 continue;
2405 break;
2406 }
2407
2408 if (!BeforeProcessingCall)
2409 return false;
2410
2411 // TODO: Clean up the unneeded nodes.
2412
2413 // Build an Epsilon node from which we will restart the analyzes.
2414 // Note that CE is permitted to be NULL!
2415 static SimpleProgramPointTag PT("ExprEngine", "Replay without inlining");
2416 ProgramPoint NewNodeLoc =
2417 EpsilonPoint(BeforeProcessingCall->getStackFrame(), CE, nullptr, &PT);
2418 // Add the special flag to GDM to signal retrying with no inlining.
2419 // Note, changing the state ensures that we are not going to cache out.
2420 // NOTE: This stores the call site (CE) in the state trait, but the the
2421 // actual pointer value is only checked by an assertion; for the analysis,
2422 // only the presence or absence of this trait matters.
2423 // TODO: If we are handling a destructor call, CE is nullpointer (because it
2424 // ultimately comes from the `Origin` of a `CXXDestructorCall`), which is
2425 // indistinguishable from the absence (default state) of this state trait.
2426 // I don't think that this bad logic causes actually observable problems, but
2427 // it would be nice to clean it up if somebody has time to do so.
2428 ProgramStateRef NewNodeState = BeforeProcessingCall->getState();
2429 NewNodeState = NewNodeState->set<ReplayWithoutInlining>(CE);
2430
2431 // Make the new node a successor of BeforeProcessingCall.
2432 bool IsNew = false;
2433 ExplodedNode *NewNode = G.getNode(L: NewNodeLoc, State: NewNodeState, IsSink: false, IsNew: &IsNew);
2434 // We cached out at this point. Caching out is common due to us backtracking
2435 // from the inlined function, which might spawn several paths.
2436 // NOTE: We must return before the `addPredecessor()` call, otherwise the
2437 // node vectors `NewNode->Preds` and `BeforeProcessingCall->Succs` would
2438 // end up containing multiple copies of `BeforeProcessingCall` / `NewNode`.
2439 if (!IsNew)
2440 return true;
2441
2442 NewNode->addPredecessor(V: BeforeProcessingCall, G);
2443
2444 // Add the new node to the work list.
2445 Engine.enqueueStmtNode(N: NewNode, Block: CalleeSF->getCallSiteBlock(),
2446 Idx: CalleeSF->getIndex());
2447 NumTimesRetriedWithoutInlining++;
2448 return true;
2449}
2450
2451/// Block entrance. (Update counters).
2452ExplodedNode *ExprEngine::processCFGBlockEntrance(const BlockEntrance &BE,
2453 ExplodedNode *Pred) {
2454 const StackFrame *SF = Pred->getStackFrame();
2455 const Stmt *Term = getCurrBlock()->getTerminatorStmt();
2456 ProgramStateRef State = Pred->getState();
2457 unsigned MaxBlockVisit = AMgr.options.maxBlockVisitOnPath;
2458
2459 // If we reach a loop which has a known bound (and meets other constraints)
2460 // then consider completely unrolling it.
2461 if (AMgr.options.ShouldUnrollLoops) {
2462 if (Term)
2463 State = updateLoopStack(LoopStmt: Term, ASTCtx&: AMgr.getASTContext(), Pred, maxVisitOnPath: MaxBlockVisit);
2464 // Is we are inside an unrolled loop then no need the check the counters.
2465 if (isUnrolledState(State))
2466 return Engine.makeNode(Loc: BE, State, Pred);
2467 }
2468
2469 // If this block is terminated by a loop and it has already been visited the
2470 // maximum number of times, widen the loop.
2471 unsigned int BlockCount = getNumVisitedCurrent();
2472 if (BlockCount == MaxBlockVisit - 1 && AMgr.options.ShouldWidenLoops) {
2473 if (!isa_and_nonnull<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(Val: Term))
2474 return Engine.makeNode(Loc: BE, State, Pred);
2475
2476 // FIXME:
2477 // We cannot use the CFG element from the via `ExprEngine::getCFGElementRef`
2478 // since we are currently at the block entrance and the current reference
2479 // would be stale. Ideally, we should pass on the terminator of the CFG
2480 // block, but the terminator cannot be referred as a CFG element.
2481 // Here we just pass the the first CFG element in the block.
2482 ProgramStateRef WidenedState = getWidenedLoopState(
2483 PrevState: State, SF, BlockCount, Elem: *getCurrBlock()->ref_begin());
2484 return Engine.makeNode(Loc: BE, State: WidenedState, Pred);
2485 }
2486
2487 // If we did not reach MaxBlockVisitOnPath, continue the analysis normally.
2488 if (BlockCount < MaxBlockVisit)
2489 return Engine.makeNode(Loc: BE, State, Pred);
2490
2491 // ... otherwise, discard this execution path.
2492 static SimpleProgramPointTag Tag(TagProviderName, "Block count exceeded");
2493 const ExplodedNode *Sink =
2494 Engine.makeNode(Loc: BE.withTag(tag: &Tag), State, Pred, /*MarkAsSink=*/true);
2495
2496 if (!SF->inTopFrame()) {
2497 // FIXME: This will unconditionally prevent inlining this function (even
2498 // from other entry points), which is not a reasonable heuristic: even if
2499 // we reached max block count on this particular execution path, there
2500 // may be other execution paths (especially with other parametrizations)
2501 // where the analyzer can reach the end of the function (so there is no
2502 // natural reason to avoid inlining it). However, disabling this would
2503 // significantly increase the analysis time (because more entry points
2504 // would exhaust their allocated budget), so it must be compensated by a
2505 // different (more reasonable) reduction of analysis scope.
2506 Engine.FunctionSummaries->markShouldNotInline(D: SF->getDecl());
2507
2508 // Re-run the call evaluation without inlining it, by storing the
2509 // no-inlining policy in the state and enqueuing the new work item on
2510 // the list. Replay should almost never fail. Use the stats to catch it
2511 // if it does.
2512 if (!AMgr.options.NoRetryExhausted && replayWithoutInlining(N: Pred, CalleeSF: SF))
2513 return nullptr;
2514 NumMaxBlockCountReachedInInlined++;
2515 } else
2516 NumMaxBlockCountReached++;
2517
2518 // Make sink nodes as exhausted(for stats) only if retry failed.
2519 Engine.blocksExhausted.push_back(x: std::make_pair(x: BE, y&: Sink));
2520
2521 return nullptr;
2522}
2523
2524void ExprEngine::runCheckersForBlockEntrance(const BlockEntrance &Entrance,
2525 ExplodedNode *Pred,
2526 ExplodedNodeSet &Dst) {
2527 llvm::PrettyStackTraceFormat CrashInfo(
2528 "Processing block entrance B%d -> B%d",
2529 Entrance.getPreviousBlock()->getBlockID(),
2530 Entrance.getBlock()->getBlockID());
2531 getCheckerManager().runCheckersForBlockEntrance(Dst, Src: Pred, Entrance, Eng&: *this);
2532}
2533
2534//===----------------------------------------------------------------------===//
2535// Branch processing.
2536//===----------------------------------------------------------------------===//
2537
2538/// RecoverCastedSymbol - A helper function for ProcessBranch that is used
2539/// to try to recover some path-sensitivity for casts of symbolic
2540/// integers that promote their values (which are currently not tracked well).
2541/// This function returns the SVal bound to Condition->IgnoreCasts if all the
2542// cast(s) did was sign-extend the original value.
2543static SVal RecoverCastedSymbol(ProgramStateRef state, const Stmt *Condition,
2544 const StackFrame *SF, ASTContext &Ctx) {
2545
2546 const auto *Ex = dyn_cast<Expr>(Val: Condition);
2547 if (!Ex)
2548 return UnknownVal();
2549
2550 uint64_t bits = 0;
2551 bool bitsInit = false;
2552
2553 while (const auto *CE = dyn_cast<CastExpr>(Val: Ex)) {
2554 QualType T = CE->getType();
2555
2556 if (!T->isIntegralOrEnumerationType())
2557 return UnknownVal();
2558
2559 uint64_t newBits = Ctx.getTypeSize(T);
2560 if (!bitsInit || newBits < bits) {
2561 bitsInit = true;
2562 bits = newBits;
2563 }
2564
2565 Ex = CE->getSubExpr();
2566 }
2567
2568 // We reached a non-cast. Is it a symbolic value?
2569 QualType T = Ex->getType();
2570
2571 if (!bitsInit || !T->isIntegralOrEnumerationType() ||
2572 Ctx.getTypeSize(T) > bits)
2573 return UnknownVal();
2574
2575 return state->getSVal(E: Ex, SF);
2576}
2577
2578#ifndef NDEBUG
2579static const Stmt *getRightmostLeaf(const Stmt *Condition) {
2580 while (Condition) {
2581 const auto *BO = dyn_cast<BinaryOperator>(Condition);
2582 if (!BO || !BO->isLogicalOp()) {
2583 return Condition;
2584 }
2585 Condition = BO->getRHS()->IgnoreParens();
2586 }
2587 return nullptr;
2588}
2589#endif
2590
2591// Returns the condition the branch at the end of 'B' depends on and whose value
2592// has been evaluated within 'B'.
2593// In most cases, the terminator condition of 'B' will be evaluated fully in
2594// the last statement of 'B'; in those cases, the resolved condition is the
2595// given 'Condition'.
2596// If the condition of the branch is a logical binary operator tree, the CFG is
2597// optimized: in that case, we know that the expression formed by all but the
2598// rightmost leaf of the logical binary operator tree must be true, and thus
2599// the branch condition is at this point equivalent to the truth value of that
2600// rightmost leaf; the CFG block thus only evaluates this rightmost leaf
2601// expression in its final statement. As the full condition in that case was
2602// not evaluated, and is thus not in the SVal cache, we need to use that leaf
2603// expression to evaluate the truth value of the condition in the current state
2604// space.
2605static const Stmt *ResolveCondition(const Stmt *Condition,
2606 const CFGBlock *B) {
2607 if (const auto *Ex = dyn_cast<Expr>(Val: Condition))
2608 Condition = Ex->IgnoreParens();
2609
2610 const auto *BO = dyn_cast<BinaryOperator>(Val: Condition);
2611 if (!BO || !BO->isLogicalOp())
2612 return Condition;
2613
2614 assert(B->getTerminator().isStmtBranch() &&
2615 "Other kinds of branches are handled separately!");
2616
2617 // For logical operations, we still have the case where some branches
2618 // use the traditional "merge" approach and others sink the branch
2619 // directly into the basic blocks representing the logical operation.
2620 // We need to distinguish between those two cases here.
2621
2622 // The invariants are still shifting, but it is possible that the
2623 // last element in a CFGBlock is not a CFGStmt. Look for the last
2624 // CFGStmt as the value of the condition.
2625 for (CFGElement Elem : llvm::reverse(C: *B)) {
2626 std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
2627 if (!CS)
2628 continue;
2629 const Stmt *LastStmt = CS->getStmt();
2630 assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition));
2631 return LastStmt;
2632 }
2633 llvm_unreachable("could not resolve condition");
2634}
2635
2636using ObjCForLctxPair =
2637 std::pair<const ObjCForCollectionStmt *, const StackFrame *>;
2638
2639REGISTER_MAP_WITH_PROGRAMSTATE(ObjCForHasMoreIterations, ObjCForLctxPair, bool)
2640
2641ProgramStateRef ExprEngine::setWhetherHasMoreIteration(
2642 ProgramStateRef State, const ObjCForCollectionStmt *O, const StackFrame *SF,
2643 bool HasMoreIteraton) {
2644 assert(!State->contains<ObjCForHasMoreIterations>({O, SF}));
2645 return State->set<ObjCForHasMoreIterations>(K: {O, SF}, E: HasMoreIteraton);
2646}
2647
2648ProgramStateRef ExprEngine::removeIterationState(ProgramStateRef State,
2649 const ObjCForCollectionStmt *O,
2650 const StackFrame *SF) {
2651 assert(State->contains<ObjCForHasMoreIterations>({O, SF}));
2652 return State->remove<ObjCForHasMoreIterations>(K: {O, SF});
2653}
2654
2655bool ExprEngine::hasMoreIteration(ProgramStateRef State,
2656 const ObjCForCollectionStmt *O,
2657 const StackFrame *SF) {
2658 assert(State->contains<ObjCForHasMoreIterations>({O, SF}));
2659 return *State->get<ObjCForHasMoreIterations>(key: {O, SF});
2660}
2661
2662/// Split the state on whether there are any more iterations left for this loop.
2663/// Returns a (HasMoreIteration, HasNoMoreIteration) pair, or std::nullopt when
2664/// the acquisition of the loop condition value failed.
2665static std::optional<std::pair<ProgramStateRef, ProgramStateRef>>
2666assumeCondition(const Stmt *ConditionStmt, ExplodedNode *N) {
2667 ProgramStateRef State = N->getState();
2668 if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(Val: ConditionStmt)) {
2669 bool HasMoreIteraton =
2670 ExprEngine::hasMoreIteration(State, O: ObjCFor, SF: N->getStackFrame());
2671 // Checkers have already ran on branch conditions, so the current
2672 // information as to whether the loop has more iteration becomes outdated
2673 // after this point.
2674 State =
2675 ExprEngine::removeIterationState(State, O: ObjCFor, SF: N->getStackFrame());
2676 if (HasMoreIteraton)
2677 return std::pair<ProgramStateRef, ProgramStateRef>{State, nullptr};
2678 else
2679 return std::pair<ProgramStateRef, ProgramStateRef>{nullptr, State};
2680 }
2681
2682 const auto *ConditionExpr = dyn_cast<Expr>(Val: ConditionStmt);
2683 assert(ConditionExpr && "The condition must be an Expr from here!");
2684
2685 SVal X = State->getSVal(E: ConditionExpr, SF: N->getStackFrame());
2686
2687 if (X.isUnknownOrUndef()) {
2688 // Give it a chance to recover from unknown.
2689 if (const auto *Ex = dyn_cast<Expr>(Val: ConditionExpr)) {
2690 if (Ex->getType()->isIntegralOrEnumerationType()) {
2691 // Try to recover some path-sensitivity. Right now casts of symbolic
2692 // integers that promote their values are currently not tracked well.
2693 // If 'ConditionExpr' is such an expression, try and recover the
2694 // underlying value and use that instead.
2695 SVal recovered =
2696 RecoverCastedSymbol(state: State, Condition: ConditionExpr, SF: N->getStackFrame(),
2697 Ctx&: N->getState()->getStateManager().getContext());
2698
2699 if (!recovered.isUnknown()) {
2700 X = recovered;
2701 }
2702 }
2703 }
2704 }
2705
2706 // If the condition is still unknown, give up.
2707 if (X.isUnknownOrUndef())
2708 return std::nullopt;
2709
2710 DefinedSVal V = X.castAs<DefinedSVal>();
2711
2712 return State->assume(Cond: V);
2713}
2714
2715void ExprEngine::processBranch(
2716 const Stmt *Condition, ExplodedNode *Pred, ExplodedNodeSet &Dst,
2717 const CFGBlock *DstT, const CFGBlock *DstF,
2718 std::optional<unsigned> IterationsCompletedInLoop) {
2719 assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) &&
2720 "CXXBindTemporaryExprs are handled by processBindTemporary.");
2721
2722 const StackFrame *SF = Pred->getStackFrame();
2723
2724 // Check for NULL conditions; e.g. "for(;;)"
2725 if (!Condition) {
2726 if (!DstT) {
2727 // I _hope_ that this "null condition + null transition to loop body"
2728 // case is impossible, but I cannot prove this, so let's cover it.
2729 return;
2730 }
2731 BlockEdge BE(getCurrBlock(), DstT, SF);
2732 Dst.insert(N: Engine.makeNode(Loc: BE, State: Pred->getState(), Pred));
2733 return;
2734 }
2735
2736 if (const auto *Ex = dyn_cast<Expr>(Val: Condition))
2737 Condition = Ex->IgnoreParens();
2738
2739 Condition = ResolveCondition(Condition, B: getCurrBlock());
2740 PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
2741 Condition->getBeginLoc(),
2742 "Error evaluating branch");
2743
2744 ExplodedNodeSet CheckersOutSet;
2745 getCheckerManager().runCheckersForBranchCondition(condition: Condition, Dst&: CheckersOutSet,
2746 Pred, Eng&: *this);
2747 // We generated only sinks.
2748 if (CheckersOutSet.empty())
2749 return;
2750
2751 for (ExplodedNode *PredN : CheckersOutSet) {
2752 ProgramStateRef PrevState = PredN->getState();
2753
2754 ProgramStateRef StTrue = PrevState, StFalse = PrevState;
2755 if (const auto KnownCondValueAssumption = assumeCondition(ConditionStmt: Condition, N: PredN))
2756 std::tie(args&: StTrue, args&: StFalse) = *KnownCondValueAssumption;
2757
2758 if (StTrue && StFalse)
2759 assert(!isa<ObjCForCollectionStmt>(Condition));
2760
2761 // We want to ensure consistent behavior between `eagerly-assume=false`,
2762 // when the state split is always performed by the `assumeCondition()`
2763 // call within this function and `eagerly-assume=true` (the default), when
2764 // some conditions (comparison operators, unary negation) can trigger a
2765 // state split before this callback. There are some contrived corner cases
2766 // that behave differently with and without `eagerly-assume`, but I don't
2767 // know about an example that could plausibly appear in "real" code.
2768 bool BothFeasible =
2769 (StTrue && StFalse) ||
2770 didEagerlyAssumeBifurcateAt(State: PrevState, Ex: dyn_cast<Expr>(Val: Condition));
2771
2772 if (StTrue) {
2773 // In a loop, if both branches are feasible (i.e. the analyzer doesn't
2774 // understand the loop condition) and two iterations have already been
2775 // completed, then don't assume a third iteration because it is a
2776 // redundant execution path (unlikely to be different from earlier loop
2777 // exits) and can cause false positives if e.g. the loop iterates over a
2778 // two-element structure with an opaque condition.
2779 //
2780 // The iteration count "2" is hardcoded because it's the natural limit:
2781 // * the fact that the programmer wrote a loop (and not just an `if`)
2782 // implies that they thought that the loop body might be executed twice;
2783 // * however, there are situations where the programmer knows that there
2784 // are at most two iterations but writes a loop that appears to be
2785 // generic, because there is no special syntax for "loop with at most
2786 // two iterations". (This pattern is common in FFMPEG and appears in
2787 // many other projects as well.)
2788 bool CompletedTwoIterations = IterationsCompletedInLoop.value_or(u: 0) >= 2;
2789 bool SkipTrueBranch = BothFeasible && CompletedTwoIterations;
2790
2791 // FIXME: This "don't assume third iteration" heuristic partially
2792 // conflicts with the widen-loop analysis option (which is off by
2793 // default). If we intend to support and stabilize the loop widening,
2794 // we must ensure that it 'plays nicely' with this logic.
2795 if (!SkipTrueBranch || AMgr.options.ShouldWidenLoops) {
2796 if (DstT) {
2797 BlockEdge BE(getCurrBlock(), DstT, SF);
2798 Dst.insert(N: Engine.makeNode(Loc: BE, State: StTrue, Pred: PredN));
2799 }
2800 } else if (!AMgr.options.InlineFunctionsWithAmbiguousLoops) {
2801 // FIXME: There is an ancient and arbitrary heuristic in
2802 // `ExprEngine::processCFGBlockEntrance` which prevents all further
2803 // inlining of a function if it finds an execution path within that
2804 // function which reaches the `MaxBlockVisitOnPath` limit (a/k/a
2805 // `analyzer-max-loop`, by default four iterations in a loop). Adding
2806 // this "don't assume third iteration" logic significantly increased
2807 // the analysis runtime on some inputs because less functions were
2808 // arbitrarily excluded from being inlined, so more entry points used
2809 // up their full allocated budget. As a hacky compensation for this,
2810 // here we apply the "should not inline" mark in cases when the loop
2811 // could potentially reach the `MaxBlockVisitOnPath` limit without the
2812 // "don't assume third iteration" logic. This slightly overcompensates
2813 // (activates if the third iteration can be entered, and will not
2814 // recognize cases where the fourth iteration would't be completed), but
2815 // should be good enough for practical purposes.
2816 if (!SF->inTopFrame()) {
2817 Engine.FunctionSummaries->markShouldNotInline(D: SF->getDecl());
2818 }
2819 }
2820 }
2821
2822 if (StFalse) {
2823 // In a loop, if both branches are feasible (i.e. the analyzer doesn't
2824 // understand the loop condition), we are before the first iteration and
2825 // the analyzer option `assume-at-least-one-iteration` is set to `true`,
2826 // then avoid creating the execution path where the loop is skipped.
2827 //
2828 // In some situations this "loop is skipped" execution path is an
2829 // important corner case that may evade the notice of the developer and
2830 // hide significant bugs -- however, there are also many situations where
2831 // it's guaranteed that at least one iteration will happen (e.g. some
2832 // data structure is always nonempty), but the analyzer cannot realize
2833 // this and will produce false positives when it assumes that the loop is
2834 // skipped.
2835 bool BeforeFirstIteration = IterationsCompletedInLoop == std::optional{0};
2836 bool SkipFalseBranch = BothFeasible && BeforeFirstIteration &&
2837 AMgr.options.ShouldAssumeAtLeastOneIteration;
2838 if (!SkipFalseBranch && DstF) {
2839 BlockEdge BE(getCurrBlock(), DstF, SF);
2840 Dst.insert(N: Engine.makeNode(Loc: BE, State: StFalse, Pred: PredN));
2841 }
2842 }
2843 }
2844}
2845
2846/// The GDM component containing the set of global variables which have been
2847/// previously initialized with explicit initializers.
2848REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,
2849 llvm::ImmutableSet<const VarDecl *>)
2850
2851void ExprEngine::processStaticInitializer(const DeclStmt *DS,
2852 ExplodedNode *Pred,
2853 ExplodedNodeSet &Dst,
2854 const CFGBlock *DstT,
2855 const CFGBlock *DstF) {
2856 const auto *VD = cast<VarDecl>(Val: DS->getSingleDecl());
2857 ProgramStateRef State = Pred->getState();
2858 bool InitHasRun = State->contains<InitializedGlobalsSet>(key: VD);
2859 if (!InitHasRun)
2860 State = State->add<InitializedGlobalsSet>(K: VD);
2861
2862 if (const CFGBlock *DstBlock = InitHasRun ? DstT : DstF) {
2863 BlockEdge BE(getCurrBlock(), DstBlock, Pred->getStackFrame());
2864 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred));
2865 }
2866}
2867
2868/// processIndirectGoto - Called by CoreEngine. Used to generate successor
2869/// nodes by processing the 'effects' of a computed goto jump.
2870void ExprEngine::processIndirectGoto(ExplodedNodeSet &Dst, const Expr *Tgt,
2871 const CFGBlock *Dispatch,
2872 ExplodedNode *Pred) {
2873 ProgramStateRef State = Pred->getState();
2874 SVal V = State->getSVal(E: Tgt, SF: getCurrStackFrame());
2875
2876 // We cannot dispatch anywhere if the label is undefined, NULL or some other
2877 // concrete number.
2878 // FIXME: Emit a warning in this situation.
2879 if (isa<UndefinedVal, loc::ConcreteInt>(Val: V))
2880 return;
2881
2882 // If 'V' is the address of a concrete goto label (on this execution path),
2883 // then only transition along the edge to that label.
2884 // FIXME: Implement dispatch for symbolic pointers, utilizing information
2885 // that they are equal or not equal to pointers to a certain goto label.
2886 const LabelDecl *L = nullptr;
2887 if (auto LV = V.getAs<loc::GotoLabel>())
2888 L = LV->getLabel();
2889
2890 // Dispatch to the label 'L' or to all labels if 'L' is null.
2891 for (const CFGBlock *Succ : Dispatch->succs()) {
2892 if (!L || cast<LabelStmt>(Val: Succ->getLabel())->getDecl() == L) {
2893 // FIXME: If 'V' was a symbolic value, then record that on this execution
2894 // path it is equal to the address of the label leading to 'Succ'.
2895 BlockEdge BE(getCurrBlock(), Succ, Pred->getStackFrame());
2896 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred));
2897 }
2898 }
2899}
2900
2901void ExprEngine::processBeginOfFunction(ExplodedNode *Pred,
2902 ExplodedNodeSet &Dst,
2903 const BlockEdge &L) {
2904 getCheckerManager().runCheckersForBeginFunction(Dst, L, Pred, Eng&: *this);
2905}
2906
2907/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
2908/// nodes when the control reaches the end of a function.
2909void ExprEngine::processEndOfFunction(ExplodedNode *Pred,
2910 const ReturnStmt *RS) {
2911 ProgramStateRef State = Pred->getState();
2912
2913 if (!Pred->getStackFrame()->inTopFrame())
2914 State = finishArgumentConstruction(
2915 State, Call: *getStateManager().getCallEventManager().getCaller(
2916 CalleeSF: Pred->getStackFrame(), State: Pred->getState()));
2917
2918 // FIXME: We currently cannot assert that temporaries are clear, because
2919 // lifetime extended temporaries are not always modelled correctly. In some
2920 // cases when we materialize the temporary, we do
2921 // createTemporaryRegionIfNeeded(), and the region changes, and also the
2922 // respective destructor becomes automatic from temporary. So for now clean up
2923 // the state manually before asserting. Ideally, this braced block of code
2924 // should go away.
2925 {
2926 const StackFrame *FromSF = Pred->getStackFrame();
2927 const StackFrame *ToSF = FromSF->getParent();
2928 const StackFrame *SF = FromSF;
2929 while (SF != ToSF) {
2930 assert(SF && "ToSF must be a parent of FromSF!");
2931 for (auto I : State->get<ObjectsUnderConstruction>())
2932 if (I.first.getStackFrame() == SF) {
2933 // The comment above only pardons us for not cleaning up a
2934 // temporary destructor. If any other statements are found here,
2935 // it must be a separate problem.
2936 assert(I.first.getItem().getKind() ==
2937 ConstructionContextItem::TemporaryDestructorKind ||
2938 I.first.getItem().getKind() ==
2939 ConstructionContextItem::ElidedDestructorKind);
2940 State = State->remove<ObjectsUnderConstruction>(K: I.first);
2941 }
2942 SF = SF->getParent();
2943 }
2944 }
2945
2946 // Perform the transition with cleanups.
2947 if (State != Pred->getState()) {
2948 Pred = Engine.makeNode(Loc: Pred->getLocation(), State, Pred);
2949 if (!Pred) {
2950 // The node with clean temporaries already exists. We might have reached
2951 // it on a path on which we initialize different temporaries.
2952 return;
2953 }
2954 }
2955
2956 assert(areAllObjectsFullyConstructed(Pred->getState(), Pred->getStackFrame(),
2957 Pred->getStackFrame()->getParent()));
2958 ExplodedNodeSet Dst;
2959 if (Pred->getStackFrame()->inTopFrame()) {
2960 // Remove dead symbols.
2961 ExplodedNodeSet AfterRemovedDead;
2962 removeDeadOnEndOfFunction(Pred, Dst&: AfterRemovedDead);
2963
2964 // Notify checkers.
2965 for (const auto I : AfterRemovedDead)
2966 getCheckerManager().runCheckersForEndFunction(Dst, Pred: I, Eng&: *this, RS);
2967 } else {
2968 getCheckerManager().runCheckersForEndFunction(Dst, Pred, Eng&: *this, RS);
2969 }
2970
2971 Engine.enqueueEndOfFunction(Set&: Dst, RS);
2972}
2973
2974/// ProcessSwitch - Called by CoreEngine. Used to generate successor
2975/// nodes by processing the 'effects' of a switch statement.
2976void ExprEngine::processSwitch(const SwitchStmt *Switch, ExplodedNode *Pred,
2977 ExplodedNodeSet &Dst) {
2978 const ASTContext &ACtx = getContext();
2979 const StackFrame *SF = Pred->getStackFrame();
2980 const Expr *Condition = Switch->getCond();
2981
2982 // The block that is terminated by the switch statement.
2983 const CFGBlock *SwitchBlock = getCurrBlock();
2984 // Note that successors may be null if they are pruned as unreachable.
2985 assert(SwitchBlock->succ_size() && "Switch must have at least one successor");
2986 // The reversed iteration order is present since the beginning, when in 2008
2987 // commit 80ebc1d1c95704b0ff0386b3a3cbc8b3ff960654 added support for handling
2988 // switch statements. I don't see any advantage over regular forward
2989 // iteration -- but switching the order would perturb the insertion order of
2990 // the work list and therefore the analysis results.
2991 llvm::iterator_range<CFGBlock::const_succ_reverse_iterator> CaseBlocks(
2992 SwitchBlock->succ_rbegin() + 1, SwitchBlock->succ_rend());
2993 const CFGBlock *DefaultBlock = *SwitchBlock->succ_rbegin();
2994
2995 ExplodedNodeSet CheckersOutSet;
2996
2997 getCheckerManager().runCheckersForBranchCondition(
2998 condition: Condition->IgnoreParens(), Dst&: CheckersOutSet, Pred, Eng&: *this);
2999
3000 for (ExplodedNode *Node : CheckersOutSet) {
3001 ProgramStateRef State = Node->getState();
3002
3003 SVal CondV = State->getSVal(E: Condition, SF);
3004 if (CondV.isUndef()) {
3005 // This can only happen if core.uninitialized.Branch is disabled.
3006 continue;
3007 }
3008 std::optional<NonLoc> CondNL = CondV.getAs<NonLoc>();
3009
3010 for (const CFGBlock *CaseBlock : CaseBlocks) {
3011 // Successor may be pruned out during CFG construction.
3012 if (!CaseBlock)
3013 continue;
3014
3015 const CaseStmt *Case = cast<CaseStmt>(Val: CaseBlock->getLabel());
3016
3017 // Evaluate the LHS of the case value.
3018 llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(Ctx: ACtx);
3019 assert(V1.getBitWidth() ==
3020 getContext().getIntWidth(Condition->getType()));
3021
3022 // Get the RHS of the case, if it exists.
3023 llvm::APSInt V2;
3024 if (const Expr *E = Case->getRHS())
3025 V2 = E->EvaluateKnownConstInt(Ctx: ACtx);
3026 else
3027 V2 = V1;
3028
3029 ProgramStateRef StateMatching;
3030 if (CondNL) {
3031 // Split the state: this "case:" matches / does not match.
3032 std::tie(args&: StateMatching, args&: State) =
3033 State->assumeInclusiveRange(Val: *CondNL, From: V1, To: V2);
3034 } else {
3035 // The switch condition is UnknownVal, so we enter each "case:" without
3036 // any state update.
3037 StateMatching = State;
3038 }
3039
3040 if (StateMatching) {
3041 BlockEdge BE(SwitchBlock, CaseBlock, SF);
3042 Dst.insert(N: Engine.makeNode(Loc: BE, State: StateMatching, Pred: Node));
3043 }
3044
3045 // If _not_ entering the current case is infeasible, then we are done
3046 // with processing the paths through the current Node.
3047 if (!State)
3048 break;
3049 }
3050 if (!State)
3051 continue;
3052
3053 // The default block may be null if it is "optimized out" by CFG creation.
3054 if (!DefaultBlock)
3055 continue;
3056
3057 // If we have switch(enum value), the default branch is not
3058 // feasible if all of the enum constants not covered by 'case:' statements
3059 // are not feasible values for the switch condition.
3060 //
3061 // Note that this isn't as accurate as it could be. Even if there isn't
3062 // a case for a particular enum value as long as that enum value isn't
3063 // feasible then it shouldn't be considered for making 'default:' reachable.
3064 if (Condition->IgnoreParenImpCasts()->getType()->isEnumeralType()) {
3065 if (Switch->isAllEnumCasesCovered())
3066 continue;
3067 }
3068
3069 BlockEdge BE(SwitchBlock, DefaultBlock, SF);
3070 Dst.insert(N: Engine.makeNode(Loc: BE, State, Pred: Node));
3071 }
3072}
3073
3074//===----------------------------------------------------------------------===//
3075// Transfer functions: Loads and stores.
3076//===----------------------------------------------------------------------===//
3077
3078std::optional<std::pair<SVal, QualType>>
3079ExprEngine::resolveAsLambdaCapturedVar(const Expr *Ex, const ValueDecl *VD,
3080 const ExplodedNode *Pred) const {
3081 ProgramStateRef State = Pred->getState();
3082 const StackFrame *SF = Pred->getStackFrame();
3083
3084 const auto *MD = dyn_cast<CXXMethodDecl>(Val: SF->getDecl());
3085 const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Val: Ex);
3086 if (!AMgr.options.ShouldInlineLambdas || !DeclRefEx ||
3087 !DeclRefEx->refersToEnclosingVariableOrCapture() || !MD ||
3088 !MD->getParent()->isLambda()) {
3089 return std::nullopt;
3090 }
3091 // Lookup the field of the lambda.
3092 const CXXRecordDecl *CXXRec = MD->getParent();
3093 llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
3094 FieldDecl *LambdaThisCaptureField;
3095 CXXRec->getCaptureFields(Captures&: LambdaCaptureFields, ThisCapture&: LambdaThisCaptureField);
3096
3097 // Sema follows a sequence of complex rules to determine whether the
3098 // variable should be captured.
3099 if (const FieldDecl *FD = LambdaCaptureFields[VD]) {
3100 if (MD->isImplicitObjectMemberFunction()) {
3101 Loc CXXThis = svalBuilder.getCXXThis(D: MD, SF);
3102 SVal CXXThisVal = State->getSVal(LV: CXXThis);
3103 return {{State->getLValue(decl: FD, Base: CXXThisVal), FD->getType()}};
3104 }
3105 const ParmVarDecl *PVD = MD->getParamDecl(i: 0);
3106 if (const Expr *CallSite = SF->getCallSite()) {
3107 const ParamVarRegion *PVR =
3108 MRMgr.getParamVarRegion(OriginExpr: CallSite, /*Index=*/0, SF);
3109 const Expr *SelfArgExpr = cast<CallExpr>(Val: CallSite)->getArg(Arg: 0);
3110 if (PVD->getType()->isReferenceType()) {
3111 // TODO: This binding should happen at call entry instead. The same way
3112 // it does for the implicit object parameter (CXXThisRegion, bound in
3113 // CXXInstanceCall::getInitialStackFrameContents). The explicit object
3114 // parameter's ParamVarRegion is never bound there today, so this
3115 // binding is just a workaround. A follow-up PR should properly bind it
3116 // at call entry, so it is no longer needed here.
3117 State =
3118 State->bindLoc(location: loc::MemRegionVal(PVR),
3119 V: State->getSVal(E: SelfArgExpr, SF: SF->getParent()), SF);
3120 SVal ParamSVal = State->getSVal(LV: loc::MemRegionVal(PVR));
3121 return {{State->getLValue(decl: FD, Base: ParamSVal), FD->getType()}};
3122 }
3123 return {{State->getLValue(decl: FD, Base: loc::MemRegionVal(PVR)), FD->getType()}};
3124 }
3125 }
3126 return std::nullopt;
3127}
3128
3129void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
3130 ExplodedNode *Pred,
3131 ExplodedNodeSet &Dst) {
3132 ProgramStateRef state = Pred->getState();
3133 const StackFrame *SF = Pred->getStackFrame();
3134
3135 if (const auto *VD = dyn_cast<VarDecl>(Val: D)) {
3136 // C permits "extern void v", and if you cast the address to a valid type,
3137 // you can even do things with it. We simply pretend
3138 assert(Ex->isGLValue() || VD->getType()->isVoidType());
3139 std::optional<std::pair<SVal, QualType>> VInfo =
3140 resolveAsLambdaCapturedVar(Ex, VD, Pred);
3141
3142 if (!VInfo)
3143 VInfo = std::make_pair(x: state->getLValue(VD, SF), y: VD->getType());
3144
3145 SVal V = VInfo->first;
3146 bool IsReference = VInfo->second->isReferenceType();
3147
3148 // For references, the 'lvalue' is the pointer address stored in the
3149 // reference region.
3150 if (IsReference) {
3151 if (const MemRegion *R = V.getAsRegion())
3152 V = state->getSVal(R);
3153 else
3154 V = UnknownVal();
3155 }
3156
3157 Dst.insert(
3158 N: Engine.makeNodeWithBinding(Pred, E: Ex, V, K: ProgramPoint::PostLValueKind));
3159 return;
3160 }
3161 if (const auto *ED = dyn_cast<EnumConstantDecl>(Val: D)) {
3162 assert(!Ex->isGLValue());
3163 SVal V = svalBuilder.makeIntVal(integer: ED->getInitVal());
3164 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: Ex, V));
3165 return;
3166 }
3167 if (const auto *FD = dyn_cast<FunctionDecl>(Val: D)) {
3168 SVal V = svalBuilder.getFunctionPointer(func: FD);
3169 Dst.insert(
3170 N: Engine.makeNodeWithBinding(Pred, E: Ex, V, K: ProgramPoint::PostLValueKind));
3171 return;
3172 }
3173 if (isa<FieldDecl, IndirectFieldDecl>(Val: D)) {
3174 // Delegate all work related to pointer to members to the surrounding
3175 // operator&.
3176 Dst.insert(N: Pred);
3177 return;
3178 }
3179 if (const auto *BD = dyn_cast<BindingDecl>(Val: D)) {
3180 // Handle structured bindings captured by lambda.
3181 if (std::optional<std::pair<SVal, QualType>> VInfo =
3182 resolveAsLambdaCapturedVar(Ex, VD: BD, Pred)) {
3183 auto [V, T] = VInfo.value();
3184
3185 if (T->isReferenceType()) {
3186 if (const MemRegion *R = V.getAsRegion())
3187 V = state->getSVal(R);
3188 else
3189 V = UnknownVal();
3190 }
3191
3192 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: Ex, V,
3193 K: ProgramPoint::PostLValueKind));
3194 return;
3195 }
3196
3197 const auto *DD = cast<DecompositionDecl>(Val: BD->getDecomposedDecl());
3198
3199 SVal Base = state->getLValue(VD: DD, SF);
3200 if (DD->getType()->isReferenceType()) {
3201 if (const MemRegion *R = Base.getAsRegion())
3202 Base = state->getSVal(R);
3203 else
3204 Base = UnknownVal();
3205 }
3206
3207 SVal V = UnknownVal();
3208
3209 // Handle binding to data members
3210 if (const auto *ME = dyn_cast<MemberExpr>(Val: BD->getBinding())) {
3211 const auto *Field = cast<FieldDecl>(Val: ME->getMemberDecl());
3212 V = state->getLValue(decl: Field, Base);
3213 }
3214 // Handle binding to arrays
3215 else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Val: BD->getBinding())) {
3216 SVal Idx = state->getSVal(E: ASE->getIdx(), SF);
3217
3218 // Note: the index of an element in a structured binding is automatically
3219 // created and it is a unique identifier of the specific element. Thus it
3220 // cannot be a value that varies at runtime.
3221 assert(Idx.isConstant() && "BindingDecl array index is not a constant!");
3222
3223 V = state->getLValue(ElementType: BD->getType(), Idx, Base);
3224 }
3225 // Handle binding to tuple-like structures
3226 else if (const auto *HV = BD->getHoldingVar()) {
3227 V = state->getLValue(VD: HV, SF);
3228
3229 if (HV->getType()->isReferenceType()) {
3230 if (const MemRegion *R = V.getAsRegion())
3231 V = state->getSVal(R);
3232 else
3233 V = UnknownVal();
3234 }
3235 } else
3236 llvm_unreachable("An unknown case of structured binding encountered!");
3237
3238 // In case of tuple-like types the references are already handled, so we
3239 // don't want to handle them again.
3240 if (BD->getType()->isReferenceType() && !BD->getHoldingVar()) {
3241 if (const MemRegion *R = V.getAsRegion())
3242 V = state->getSVal(R);
3243 else
3244 V = UnknownVal();
3245 }
3246
3247 Dst.insert(
3248 N: Engine.makeNodeWithBinding(Pred, E: Ex, V, K: ProgramPoint::PostLValueKind));
3249 return;
3250 }
3251
3252 if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(Val: D)) {
3253 // FIXME: We should meaningfully implement this.
3254 (void)TPO;
3255 Dst.insert(N: Pred);
3256 return;
3257 }
3258
3259 llvm_unreachable("Support for this Decl not implemented.");
3260}
3261
3262/// VisitArrayInitLoopExpr - Transfer function for array init loop.
3263void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex,
3264 ExplodedNode *Pred,
3265 ExplodedNodeSet &Dst) {
3266 const Expr *Arr = Ex->getCommonExpr()->getSourceExpr();
3267
3268 // The constructor visitor has already handled everything
3269 if (isa<CXXConstructExpr>(Val: Ex->getSubExpr())) {
3270 Dst.insert(N: Pred);
3271 return;
3272 }
3273
3274 const StackFrame *SF = Pred->getStackFrame();
3275 ProgramStateRef state = Pred->getState();
3276
3277 SVal Base = UnknownVal();
3278
3279 // As in case of this expression the sub-expressions are not visited by any
3280 // other transfer functions, they are handled by matching their AST.
3281
3282 // Case of implicit copy or move ctor of object with array member
3283 //
3284 // Note: ExprEngine::VisitMemberExpr is not able to bind the array to the
3285 // environment.
3286 //
3287 // struct S {
3288 // int arr[2];
3289 // };
3290 //
3291 //
3292 // S a;
3293 // S b = a;
3294 //
3295 // The AST in case of a *copy constructor* looks like this:
3296 // ArrayInitLoopExpr
3297 // |-OpaqueValueExpr
3298 // | `-MemberExpr <-- match this
3299 // | `-DeclRefExpr
3300 // ` ...
3301 //
3302 //
3303 // S c;
3304 // S d = std::move(d);
3305 //
3306 // In case of a *move constructor* the resulting AST looks like:
3307 // ArrayInitLoopExpr
3308 // |-OpaqueValueExpr
3309 // | `-MemberExpr <-- match this first
3310 // | `-CXXStaticCastExpr <-- match this after
3311 // | `-DeclRefExpr
3312 // ` ...
3313 if (const auto *ME = dyn_cast<MemberExpr>(Val: Arr)) {
3314 Expr *MEBase = ME->getBase();
3315
3316 // Move ctor
3317 if (auto CXXSCE = dyn_cast<CXXStaticCastExpr>(Val: MEBase)) {
3318 MEBase = CXXSCE->getSubExpr();
3319 }
3320
3321 auto ObjDeclExpr = cast<DeclRefExpr>(Val: MEBase);
3322 SVal Obj = state->getLValue(VD: cast<VarDecl>(Val: ObjDeclExpr->getDecl()), SF);
3323
3324 Base = state->getLValue(decl: cast<FieldDecl>(Val: ME->getMemberDecl()), Base: Obj);
3325 }
3326
3327 // Case of lambda capture and decomposition declaration
3328 //
3329 // int arr[2];
3330 //
3331 // [arr]{ int a = arr[0]; }();
3332 // auto[a, b] = arr;
3333 //
3334 // In both of these cases the AST looks like the following:
3335 // ArrayInitLoopExpr
3336 // |-OpaqueValueExpr
3337 // | `-DeclRefExpr <-- match this
3338 // ` ...
3339 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Val: Arr))
3340 Base = state->getLValue(VD: cast<VarDecl>(Val: DRE->getDecl()), SF);
3341
3342 // Create a lazy compound value to the original array
3343 if (const MemRegion *R = Base.getAsRegion())
3344 Base = state->getSVal(R);
3345 else
3346 Base = UnknownVal();
3347
3348 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: Ex, V: Base));
3349}
3350
3351/// VisitArraySubscriptExpr - Transfer function for array accesses
3352void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A,
3353 ExplodedNode *Pred,
3354 ExplodedNodeSet &Dst) {
3355 const Expr *Base = A->getBase()->IgnoreParens();
3356 const Expr *Idx = A->getIdx()->IgnoreParens();
3357
3358 bool IsVectorType = A->getBase()->getType()->isVectorType();
3359
3360 // The "like" case is for situations where C standard prohibits the type to
3361 // be an lvalue, e.g. taking the address of a subscript of an expression of
3362 // type "void *".
3363 bool IsGLValueLike = A->isGLValue() ||
3364 (A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus);
3365
3366 const StackFrame *SF = Pred->getStackFrame();
3367 ProgramStateRef state = Pred->getState();
3368
3369 if (IsGLValueLike) {
3370 QualType T = A->getType();
3371
3372 // One of the forbidden LValue types! We still need to have sensible
3373 // symbolic locations to represent this stuff. Note that arithmetic on
3374 // void pointers is a GCC extension.
3375 if (T->isVoidType())
3376 T = getContext().CharTy;
3377
3378 SVal V =
3379 state->getLValue(ElementType: T, Idx: state->getSVal(E: Idx, SF), Base: state->getSVal(E: Base, SF));
3380 Dst.insert(
3381 N: Engine.makeNodeWithBinding(Pred, E: A, V, K: ProgramPoint::PostLValueKind));
3382 } else if (IsVectorType) {
3383 // FIXME: non-glvalue vector reads are not modelled.
3384 Dst.insert(N: Engine.makePostStmtNode(S: A, State: state, Pred));
3385 } else {
3386 llvm_unreachable("Array subscript should be an lValue when not \
3387a vector and not a forbidden lvalue type");
3388 }
3389}
3390
3391/// VisitMemberExpr - Transfer function for member expressions.
3392void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
3393 ExplodedNodeSet &Dst) {
3394 ValueDecl *Member = M->getMemberDecl();
3395
3396 // Handle static member variables and enum constants accessed via
3397 // member syntax.
3398 if (isa<VarDecl, EnumConstantDecl>(Val: Member)) {
3399 VisitCommonDeclRefExpr(Ex: M, D: Member, Pred, Dst);
3400 return;
3401 }
3402
3403 ProgramStateRef state = Pred->getState();
3404 const StackFrame *SF = Pred->getStackFrame();
3405 Expr *BaseExpr = M->getBase();
3406
3407 // Handle C++ method calls.
3408 if (const auto *MD = dyn_cast<CXXMethodDecl>(Val: Member)) {
3409 if (MD->isImplicitObjectMemberFunction())
3410 state = createTemporaryRegionIfNeeded(State: state, SF, InitWithAdjustments: BaseExpr);
3411
3412 SVal MDVal = svalBuilder.getFunctionPointer(func: MD);
3413
3414 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: M, V: MDVal, State: state));
3415 return;
3416 }
3417
3418 // Handle regular struct fields / member variables.
3419 const SubRegion *MR = nullptr;
3420 state = createTemporaryRegionIfNeeded(State: state, SF, InitWithAdjustments: BaseExpr,
3421 /*Result=*/nullptr,
3422 /*OutRegionWithAdjustments=*/&MR);
3423 SVal baseExprVal = MR ? loc::MemRegionVal(MR) : state->getSVal(E: BaseExpr, SF);
3424
3425 // FIXME: Copied from RegionStoreManager::bind()
3426 if (const auto *SR =
3427 dyn_cast_or_null<SymbolicRegion>(Val: baseExprVal.getAsRegion())) {
3428 QualType T = SR->getPointeeStaticType();
3429 baseExprVal =
3430 loc::MemRegionVal(getStoreManager().GetElementZeroRegion(R: SR, T));
3431 }
3432
3433 const auto *field = cast<FieldDecl>(Val: Member);
3434 SVal L = state->getLValue(decl: field, Base: baseExprVal);
3435
3436 if (M->isGLValue() || M->getType()->isArrayType()) {
3437 // We special-case rvalues of array type because the analyzer cannot
3438 // reason about them, since we expect all regions to be wrapped in Locs.
3439 // We instead treat these as lvalues and assume that they will decay to
3440 // pointers as soon as they are used.
3441 if (!M->isGLValue()) {
3442 assert(M->getType()->isArrayType());
3443 const auto *PE = dyn_cast<ImplicitCastExpr>(
3444 Val: Pred->getParentMap().getParentIgnoreParens(S: M));
3445 if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) {
3446 llvm_unreachable("should always be wrapped in ArrayToPointerDecay");
3447 }
3448 }
3449
3450 if (field->getType()->isReferenceType()) {
3451 if (const MemRegion *R = L.getAsRegion())
3452 L = state->getSVal(R);
3453 else
3454 L = UnknownVal();
3455 }
3456
3457 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: M, V: L, State: state,
3458 K: ProgramPoint::PostLValueKind));
3459 } else {
3460 evalLoad(Dst, NodeEx: M, BoundExpr: M, Pred, St: state, location: L);
3461 }
3462}
3463
3464void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
3465 ExplodedNodeSet &Dst) {
3466 // For now, treat all the arguments to C11 atomics as escaping.
3467 // FIXME: Ideally we should model the behavior of the atomics precisely here.
3468
3469 ProgramStateRef State = Pred->getState();
3470 const StackFrame *SF = Pred->getStackFrame();
3471
3472 SmallVector<SVal, 8> ValuesToInvalidate;
3473 for (const Stmt *SubExpr : AE->children()) {
3474 SVal SubExprVal = State->getSVal(E: cast<Expr>(Val: SubExpr), SF);
3475 ValuesToInvalidate.push_back(Elt: SubExprVal);
3476 }
3477
3478 State = State->invalidateRegions(Values: ValuesToInvalidate, Elem: getCFGElementRef(),
3479 BlockCount: getNumVisitedCurrent(), SF,
3480 /*CausedByPointerEscape*/ CausesPointerEscape: true,
3481 /*Symbols=*/IS: nullptr);
3482
3483 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E: AE, V: UnknownVal(), State));
3484}
3485
3486// A value escapes in four possible cases:
3487// (1) We are binding to something that is not a memory region.
3488// (2) We are binding to a MemRegion that does not have stack storage.
3489// (3) We are binding to a top-level parameter region with a non-trivial
3490// destructor. We won't see the destructor during analysis, but it's there.
3491// (4) We are binding to a MemRegion with stack storage that the store
3492// does not understand.
3493ProgramStateRef ExprEngine::processPointerEscapedOnBind(
3494 ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals,
3495 const StackFrame *SF, PointerEscapeKind Kind, const CallEvent *Call) {
3496 SmallVector<SVal, 8> Escaped;
3497 for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
3498 // Cases (1) and (2).
3499 const MemRegion *MR = LocAndVal.first.getAsRegion();
3500 const MemSpaceRegion *Space = MR ? MR->getMemorySpace(State) : nullptr;
3501 if (!MR || !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(Val: Space)) {
3502 Escaped.push_back(Elt: LocAndVal.second);
3503 continue;
3504 }
3505
3506 // Case (3).
3507 if (const auto *VR = dyn_cast<VarRegion>(Val: MR->getBaseRegion()))
3508 if (isa<StackArgumentsSpaceRegion>(Val: Space) &&
3509 VR->getStackFrame()->inTopFrame())
3510 if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
3511 if (!RD->hasTrivialDestructor()) {
3512 Escaped.push_back(Elt: LocAndVal.second);
3513 continue;
3514 }
3515
3516 // Case (4): in order to test that, generate a new state with the binding
3517 // added. If it is the same state, then it escapes (since the store cannot
3518 // represent the binding).
3519 // Do this only if we know that the store is not supposed to generate the
3520 // same state.
3521 SVal StoredVal = State->getSVal(R: MR);
3522 if (StoredVal != LocAndVal.second)
3523 if (State ==
3524 (State->bindLoc(location: loc::MemRegionVal(MR), V: LocAndVal.second, SF)))
3525 Escaped.push_back(Elt: LocAndVal.second);
3526 }
3527
3528 if (Escaped.empty())
3529 return State;
3530
3531 return escapeValues(State, Vs: Escaped, K: Kind, Call);
3532}
3533
3534ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
3535 SVal Loc, SVal Val,
3536 const StackFrame *SF) {
3537 std::pair<SVal, SVal> LocAndVal(Loc, Val);
3538 return processPointerEscapedOnBind(State, LocAndVals: LocAndVal, SF, Kind: PSK_EscapeOnBind,
3539 Call: nullptr);
3540}
3541
3542ProgramStateRef
3543ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
3544 const InvalidatedSymbols *Invalidated,
3545 ArrayRef<const MemRegion *> ExplicitRegions,
3546 const CallEvent *Call,
3547 RegionAndSymbolInvalidationTraits &ITraits) {
3548 if (!Invalidated || Invalidated->empty())
3549 return State;
3550
3551 if (!Call)
3552 return getCheckerManager().runCheckersForPointerEscape(State,
3553 Escaped: *Invalidated,
3554 Call: nullptr,
3555 Kind: PSK_EscapeOther,
3556 ITraits: &ITraits);
3557
3558 // If the symbols were invalidated by a call, we want to find out which ones
3559 // were invalidated directly due to being arguments to the call.
3560 InvalidatedSymbols SymbolsDirectlyInvalidated;
3561 for (const auto I : ExplicitRegions) {
3562 if (const SymbolicRegion *R = I->StripCasts()->getAs<SymbolicRegion>())
3563 SymbolsDirectlyInvalidated.insert(V: R->getSymbol());
3564 }
3565
3566 InvalidatedSymbols SymbolsIndirectlyInvalidated;
3567 for (const auto &sym : *Invalidated) {
3568 if (SymbolsDirectlyInvalidated.count(V: sym))
3569 continue;
3570 SymbolsIndirectlyInvalidated.insert(V: sym);
3571 }
3572
3573 if (!SymbolsDirectlyInvalidated.empty())
3574 State = getCheckerManager().runCheckersForPointerEscape(State,
3575 Escaped: SymbolsDirectlyInvalidated, Call, Kind: PSK_DirectEscapeOnCall, ITraits: &ITraits);
3576
3577 // Notify about the symbols that get indirectly invalidated by the call.
3578 if (!SymbolsIndirectlyInvalidated.empty())
3579 State = getCheckerManager().runCheckersForPointerEscape(State,
3580 Escaped: SymbolsIndirectlyInvalidated, Call, Kind: PSK_IndirectEscapeOnCall, ITraits: &ITraits);
3581
3582 return State;
3583}
3584
3585/// evalBind - Handle the semantics of binding a value to a specific location.
3586/// This method is used by evalStore, VisitDeclStmt, and others.
3587void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
3588 ExplodedNode *Pred, SVal Location, SVal Val,
3589 bool AtDeclInit, const ProgramPoint *PP) {
3590
3591 // It may be a Loc, UnknownVal or perhaps UndefinedVal.
3592 assert(!isa<NonLoc>(Location) && "evalBind location should not be NonLoc!");
3593
3594 const StackFrame *SF = Pred->getStackFrame();
3595 PostStmt DefaultPP(StoreE, SF);
3596
3597 if (!PP)
3598 PP = &DefaultPP;
3599
3600 // Do a previsit of the bind.
3601 ExplodedNodeSet CheckedSet;
3602 getCheckerManager().runCheckersForBind(Dst&: CheckedSet, Src: Pred, location: Location, val: Val,
3603 S: StoreE, AtDeclInit, Eng&: *this, PP: *PP);
3604
3605 for (ExplodedNode *PredI : CheckedSet) {
3606 ProgramStateRef State = PredI->getState();
3607
3608 // Check and record that 'Val' may escape:
3609 State = processPointerEscapedOnBind(State, Loc: Location, Val, SF);
3610
3611 if (auto AsLoc = Location.getAs<Loc>()) {
3612 // When binding the value, pass on the hint that this is a
3613 // initialization. For initializations, we do not need to inform clients
3614 // of region changes.
3615 State = State->bindLoc(location: *AsLoc, V: Val, SF, /*notifyChanges=*/!AtDeclInit);
3616 }
3617
3618 PostStore PS(StoreE, SF, Location.getAsRegion(), /*tag=*/nullptr);
3619 Dst.insert(N: Engine.makeNode(Loc: PS, State, Pred: PredI));
3620 }
3621}
3622
3623/// evalStore - Handle the semantics of a store via an assignment.
3624/// @param Dst The node set to store generated state nodes
3625/// @param AssignE The assignment expression if the store happens in an
3626/// assignment.
3627/// @param LocationE The location expression that is stored to.
3628/// @param state The current simulation state
3629/// @param location The location to store the value
3630/// @param Val The value to be stored
3631void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE,
3632 const Expr *LocationE,
3633 ExplodedNode *Pred,
3634 ProgramStateRef state, SVal location, SVal Val,
3635 const ProgramPointTag *tag) {
3636 // Proceed with the store. We use AssignE as the anchor for the PostStore
3637 // ProgramPoint if it is non-NULL, and LocationE otherwise.
3638 const Expr *StoreE = AssignE ? AssignE : LocationE;
3639
3640 // Evaluate the location (checks for bad dereferences).
3641 ExplodedNodeSet Tmp;
3642 evalLocation(Dst&: Tmp, NodeEx: AssignE, BoundEx: LocationE, Pred, St: state, location, isLoad: false);
3643
3644 if (Tmp.empty())
3645 return;
3646
3647 if (location.isUndef())
3648 return;
3649
3650 for (const auto I : Tmp)
3651 evalBind(Dst, StoreE, Pred: I, Location: location, Val, AtDeclInit: false);
3652}
3653
3654void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
3655 const Expr *NodeEx,
3656 const Expr *BoundEx,
3657 ExplodedNode *Pred,
3658 ProgramStateRef state,
3659 SVal location,
3660 const ProgramPointTag *tag,
3661 QualType LoadTy) {
3662 assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
3663 assert(NodeEx);
3664 assert(BoundEx);
3665 // Evaluate the location (checks for bad dereferences).
3666 ExplodedNodeSet Tmp;
3667 evalLocation(Dst&: Tmp, NodeEx, BoundEx, Pred, St: state, location, isLoad: true);
3668 if (Tmp.empty())
3669 return;
3670
3671 if (location.isUndef()) {
3672 Dst.insert(S: Tmp);
3673 return;
3674 }
3675
3676 // Proceed with the load.
3677 for (const auto I : Tmp) {
3678 state = I->getState();
3679
3680 SVal V = UnknownVal();
3681 if (location.isValid()) {
3682 if (LoadTy.isNull())
3683 LoadTy = BoundEx->getType();
3684 V = state->getSVal(LV: location.castAs<Loc>(), T: LoadTy);
3685 }
3686
3687 const auto *SF = I->getStackFrame();
3688 PostLoad Loc(NodeEx, SF, tag);
3689 Dst.insert(N: Engine.makeNode(Loc, State: state->BindExpr(E: BoundEx, SF, V), Pred: I));
3690 }
3691}
3692
3693void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *NodeEx,
3694 const Stmt *BoundEx, ExplodedNode *Pred,
3695 ProgramStateRef state, SVal location,
3696 bool isLoad) {
3697 // Early checks for performance reason.
3698 if (location.isUnknown()) {
3699 Dst.insert(N: Pred);
3700 return;
3701 }
3702
3703 ExplodedNodeSet Src;
3704 if (Pred->getState() == state) {
3705 Src.insert(N: Pred);
3706 } else {
3707 // Associate this new state with an ExplodedNode.
3708 // FIXME: If I pass null tag, the graph is incorrect, e.g for
3709 // int *p;
3710 // p = 0;
3711 // *p = 0xDEADBEEF;
3712 // "p = 0" is not noted as "Null pointer value stored to 'p'" but
3713 // instead "int *p" is noted as
3714 // "Variable 'p' initialized to a null pointer value"
3715
3716 static SimpleProgramPointTag tag(TagProviderName, "Location");
3717 PostStmt Loc(NodeEx, Pred->getStackFrame(), &tag);
3718 Src.insert(N: Engine.makeNode(Loc, State: state, Pred));
3719 }
3720
3721 ExplodedNodeSet Tmp;
3722 getCheckerManager().runCheckersForLocation(Dst&: Tmp, Src, location, isLoad,
3723 NodeEx, BoundEx, Eng&: *this);
3724 Dst.insert(S: Tmp);
3725}
3726
3727std::pair<const ProgramPointTag *, const ProgramPointTag *>
3728ExprEngine::getEagerlyAssumeBifurcationTags() {
3729 static SimpleProgramPointTag TrueTag(TagProviderName, "Eagerly Assume True"),
3730 FalseTag(TagProviderName, "Eagerly Assume False");
3731
3732 return std::make_pair(x: &TrueTag, y: &FalseTag);
3733}
3734
3735/// If the last EagerlyAssume attempt was successful (i.e. the true and false
3736/// cases were both feasible), this state trait stores the expression where it
3737/// happened; otherwise this holds nullptr.
3738REGISTER_TRAIT_WITH_PROGRAMSTATE(LastEagerlyAssumeExprIfSuccessful,
3739 const Expr *)
3740
3741void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst,
3742 ExplodedNodeSet &Src,
3743 const Expr *Ex) {
3744 for (ExplodedNode *Pred : Src) {
3745 const StackFrame *SF = Pred->getStackFrame();
3746 // Test if the previous node was as the same expression. This can happen
3747 // when the expression fails to evaluate to anything meaningful and
3748 // (as an optimization) we don't generate a node.
3749 ProgramPoint P = Pred->getLocation();
3750 if (!P.getAs<PostStmt>() || P.castAs<PostStmt>().getStmt() != Ex) {
3751 Dst.insert(N: Pred);
3752 continue;
3753 }
3754
3755 ProgramStateRef State = Pred->getState();
3756 State = State->set<LastEagerlyAssumeExprIfSuccessful>(nullptr);
3757 SVal V = State->getSVal(E: Ex, SF);
3758 std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
3759 if (SEV && SEV->isExpression()) {
3760 const auto &[TrueTag, FalseTag] = getEagerlyAssumeBifurcationTags();
3761
3762 auto [StateTrue, StateFalse] = State->assume(Cond: *SEV);
3763
3764 if (StateTrue && StateFalse) {
3765 StateTrue = StateTrue->set<LastEagerlyAssumeExprIfSuccessful>(Ex);
3766 StateFalse = StateFalse->set<LastEagerlyAssumeExprIfSuccessful>(Ex);
3767 }
3768
3769 // First assume that the condition is true.
3770 if (StateTrue) {
3771 SVal Val = svalBuilder.makeIntVal(integer: 1U, type: Ex->getType());
3772 StateTrue = StateTrue->BindExpr(E: Ex, SF, V: Val);
3773 PostStmt PostStmtTrue(Ex, SF, TrueTag);
3774 Dst.insert(N: Engine.makeNode(Loc: PostStmtTrue, State: StateTrue, Pred));
3775 }
3776
3777 // Next, assume that the condition is false.
3778 if (StateFalse) {
3779 SVal Val = svalBuilder.makeIntVal(integer: 0U, type: Ex->getType());
3780 StateFalse = StateFalse->BindExpr(E: Ex, SF, V: Val);
3781 PostStmt PostStmtFalse(Ex, SF, FalseTag);
3782 Dst.insert(N: Engine.makeNode(Loc: PostStmtFalse, State: StateFalse, Pred));
3783 }
3784 } else {
3785 Dst.insert(N: Pred);
3786 }
3787 }
3788}
3789
3790bool ExprEngine::didEagerlyAssumeBifurcateAt(ProgramStateRef State,
3791 const Expr *Ex) const {
3792 return Ex && State->get<LastEagerlyAssumeExprIfSuccessful>() == Ex;
3793}
3794
3795void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
3796 ExplodedNodeSet &Dst) {
3797 // We have processed both the inputs and the outputs. All of the outputs
3798 // should evaluate to Locs. Nuke all of their values.
3799
3800 // FIXME: Some day in the future it would be nice to allow a "plug-in"
3801 // which interprets the inline asm and stores proper results in the
3802 // outputs.
3803
3804 ProgramStateRef state = Pred->getState();
3805
3806 for (const Expr *O : A->outputs()) {
3807 SVal X = state->getSVal(E: O, SF: Pred->getStackFrame());
3808 assert(!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
3809
3810 if (std::optional<Loc> LV = X.getAs<Loc>())
3811 state = state->invalidateRegions(Values: *LV, Elem: getCFGElementRef(),
3812 BlockCount: getNumVisitedCurrent(),
3813 SF: Pred->getStackFrame(),
3814 /*CausedByPointerEscape=*/CausesPointerEscape: true);
3815 }
3816
3817 // Do not reason about locations passed inside inline assembly.
3818 for (const Expr *I : A->inputs()) {
3819 SVal X = state->getSVal(E: I, SF: Pred->getStackFrame());
3820
3821 if (std::optional<Loc> LV = X.getAs<Loc>())
3822 state = state->invalidateRegions(Values: *LV, Elem: getCFGElementRef(),
3823 BlockCount: getNumVisitedCurrent(),
3824 SF: Pred->getStackFrame(),
3825 /*CausedByPointerEscape=*/CausesPointerEscape: true);
3826 }
3827
3828 Dst.insert(N: Engine.makePostStmtNode(S: A, State: state, Pred));
3829}
3830
3831void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
3832 ExplodedNodeSet &Dst) {
3833 Dst.insert(N: Engine.makePostStmtNode(S: A, State: Pred->getState(), Pred));
3834}
3835
3836//===----------------------------------------------------------------------===//
3837// Visualization.
3838//===----------------------------------------------------------------------===//
3839
3840namespace llvm {
3841
3842template<>
3843struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
3844 DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
3845
3846 static bool nodeHasBugReport(const ExplodedNode *N) {
3847 BugReporter &BR = static_cast<ExprEngine &>(
3848 N->getState()->getStateManager().getOwningEngine()).getBugReporter();
3849
3850 for (const auto &Class : BR.equivalenceClasses()) {
3851 for (const auto &Report : Class.getReports()) {
3852 const auto *PR = dyn_cast<PathSensitiveBugReport>(Val: Report.get());
3853 if (!PR)
3854 continue;
3855 const ExplodedNode *EN = PR->getErrorNode();
3856 if (EN->getState() == N->getState() &&
3857 EN->getLocation() == N->getLocation())
3858 return true;
3859 }
3860 }
3861 return false;
3862 }
3863
3864 /// \p PreCallback: callback before break.
3865 /// \p PostCallback: callback after break.
3866 /// \p Stop: stop iteration if returns @c true
3867 /// \return Whether @c Stop ever returned @c true.
3868 static bool traverseHiddenNodes(
3869 const ExplodedNode *N,
3870 llvm::function_ref<void(const ExplodedNode *)> PreCallback,
3871 llvm::function_ref<void(const ExplodedNode *)> PostCallback,
3872 llvm::function_ref<bool(const ExplodedNode *)> Stop) {
3873 while (true) {
3874 PreCallback(N);
3875 if (Stop(N))
3876 return true;
3877
3878 if (N->succ_size() != 1 || !isNodeHidden(N: N->getFirstSucc(), G: nullptr))
3879 break;
3880 PostCallback(N);
3881
3882 N = N->getFirstSucc();
3883 }
3884 return false;
3885 }
3886
3887 static bool isNodeHidden(const ExplodedNode *N, const ExplodedGraph *G) {
3888 return N->isTrivial();
3889 }
3890
3891 static std::string getNodeLabel(const ExplodedNode *N, ExplodedGraph *G){
3892 std::string Buf;
3893 llvm::raw_string_ostream Out(Buf);
3894
3895 const bool IsDot = true;
3896 const unsigned int Space = 1;
3897 ProgramStateRef State = N->getState();
3898
3899 Out << "{ \"state_id\": " << State->getID()
3900 << ",\\l";
3901
3902 Indent(Out, Space, IsDot) << "\"program_points\": [\\l";
3903
3904 // Dump program point for all the previously skipped nodes.
3905 traverseHiddenNodes(
3906 N,
3907 PreCallback: [&](const ExplodedNode *OtherNode) {
3908 Indent(Out, Space: Space + 1, IsDot) << "{ ";
3909 OtherNode->getLocation().printJson(Out, /*NL=*/"\\l");
3910 Out << ", \"tag\": ";
3911 if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag())
3912 Out << '\"' << Tag->getDebugTag() << '\"';
3913 else
3914 Out << "null";
3915 Out << ", \"node_id\": " << OtherNode->getID() <<
3916 ", \"is_sink\": " << OtherNode->isSink() <<
3917 ", \"has_report\": " << nodeHasBugReport(N: OtherNode) << " }";
3918 },
3919 // Adds a comma and a new-line between each program point.
3920 PostCallback: [&](const ExplodedNode *) { Out << ",\\l"; },
3921 Stop: [&](const ExplodedNode *) { return false; });
3922
3923 Out << "\\l"; // Adds a new-line to the last program point.
3924 Indent(Out, Space, IsDot) << "],\\l";
3925
3926 State->printDOT(Out, SF: N->getStackFrame(), Space);
3927
3928 Out << "\\l}\\l";
3929 return Buf;
3930 }
3931};
3932
3933} // namespace llvm
3934
3935void ExprEngine::ViewGraph(bool trim) {
3936 std::string Filename = DumpGraph(trim);
3937 llvm::DisplayGraph(Filename, wait: false, program: llvm::GraphProgram::DOT);
3938}
3939
3940void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode *> Nodes) {
3941 std::string Filename = DumpGraph(Nodes);
3942 llvm::DisplayGraph(Filename, wait: false, program: llvm::GraphProgram::DOT);
3943}
3944
3945std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) {
3946 if (trim) {
3947 std::vector<const ExplodedNode *> Src;
3948
3949 // Iterate through the reports and get their nodes.
3950 for (const auto &Class : BR.equivalenceClasses()) {
3951 const auto *R =
3952 dyn_cast<PathSensitiveBugReport>(Val: Class.getReports()[0].get());
3953 if (!R)
3954 continue;
3955 const auto *N = const_cast<ExplodedNode *>(R->getErrorNode());
3956 Src.push_back(x: N);
3957 }
3958 return DumpGraph(Nodes: Src, Filename);
3959 }
3960
3961 // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
3962 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
3963 return llvm::WriteGraph(G: &G, Name: "ExprEngine", /*ShortNames=*/false,
3964 /*Title=*/"Exploded Graph",
3965 /*Filename=*/std::string(Filename));
3966}
3967
3968std::string ExprEngine::DumpGraph(ArrayRef<const ExplodedNode *> Nodes,
3969 StringRef Filename) {
3970 std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes));
3971
3972 if (!TrimmedG) {
3973 llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
3974 return "";
3975 }
3976
3977 // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
3978 auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
3979 return llvm::WriteGraph(G: TrimmedG.get(), Name: "TrimmedExprEngine",
3980 /*ShortNames=*/false,
3981 /*Title=*/"Trimmed Exploded Graph",
3982 /*Filename=*/std::string(Filename));
3983}
3984
3985void *ProgramStateTrait<ReplayWithoutInlining>::GDMIndex() {
3986 static int index = 0;
3987 return &index;
3988}
3989
3990void ExprEngine::anchor() { }
3991
3992void ExprEngine::ConstructInitList(const Expr *E, ArrayRef<Expr *> Args,
3993 bool IsTransparent, ExplodedNode *Pred,
3994 ExplodedNodeSet &Dst) {
3995 assert((isa<InitListExpr, CXXParenListInitExpr>(E)));
3996
3997 const StackFrame *SF = Pred->getStackFrame();
3998
3999 ProgramStateRef S = Pred->getState();
4000 QualType T = E->getType().getCanonicalType();
4001
4002 bool IsCompound = T->isArrayType() || T->isRecordType() ||
4003 T->isAnyComplexType() || T->isVectorType();
4004
4005 SVal Val;
4006 if (Args.size() > 1 || (E->isPRValue() && IsCompound && !IsTransparent)) {
4007 llvm::ImmutableList<SVal> ArgList = getBasicVals().getEmptySValList();
4008 for (Expr *E : llvm::reverse(C&: Args))
4009 ArgList = getBasicVals().prependSVal(X: S->getSVal(E, SF), L: ArgList);
4010
4011 Val = getSValBuilder().makeCompoundVal(type: T, vals: ArgList);
4012 } else if (Args.size() == 0) {
4013 Val = getSValBuilder().makeZeroVal(type: T);
4014 } else {
4015 Val = S->getSVal(E: Args.front(), SF);
4016 }
4017 Dst.insert(N: Engine.makeNodeWithBinding(Pred, E, V: Val));
4018}
4019