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