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