10b57cec5SDimitry Andric //===- ExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ----------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines a meta-engine for path-sensitive dataflow analysis that 1081ad6265SDimitry Andric // is built on CoreEngine, but provides the boilerplate to execute transfer 110b57cec5SDimitry Andric // functions and build the ExplodedGraph at the expression level. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 160b57cec5SDimitry Andric #include "PrettyStackTraceLocationContext.h" 170b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 180b57cec5SDimitry Andric #include "clang/AST/Decl.h" 190b57cec5SDimitry Andric #include "clang/AST/DeclBase.h" 200b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h" 210b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h" 220b57cec5SDimitry Andric #include "clang/AST/Expr.h" 230b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h" 240b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h" 250b57cec5SDimitry Andric #include "clang/AST/ParentMap.h" 260b57cec5SDimitry Andric #include "clang/AST/PrettyPrinter.h" 270b57cec5SDimitry Andric #include "clang/AST/Stmt.h" 280b57cec5SDimitry Andric #include "clang/AST/StmtCXX.h" 290b57cec5SDimitry Andric #include "clang/AST/StmtObjC.h" 300b57cec5SDimitry Andric #include "clang/AST/Type.h" 310b57cec5SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h" 320b57cec5SDimitry Andric #include "clang/Analysis/CFG.h" 330b57cec5SDimitry Andric #include "clang/Analysis/ConstructionContext.h" 340b57cec5SDimitry Andric #include "clang/Analysis/ProgramPoint.h" 350b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h" 360b57cec5SDimitry Andric #include "clang/Basic/JsonSupport.h" 370b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 380b57cec5SDimitry Andric #include "clang/Basic/LangOptions.h" 390b57cec5SDimitry Andric #include "clang/Basic/PrettyStackTrace.h" 400b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h" 410b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 420b57cec5SDimitry Andric #include "clang/Basic/Specifiers.h" 430b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" 440b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 450b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 460b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 470b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 480b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 490b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" 500b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" 51bdd1243dSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" 520b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 530b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h" 540b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h" 550b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" 560b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 570b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 580b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" 590b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" 600b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 610b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" 620b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" 630b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 640b57cec5SDimitry Andric #include "llvm/ADT/APSInt.h" 650b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 660b57cec5SDimitry Andric #include "llvm/ADT/ImmutableMap.h" 670b57cec5SDimitry Andric #include "llvm/ADT/ImmutableSet.h" 6806c3fb27SDimitry Andric #include "llvm/ADT/STLExtras.h" 690b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 700b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 710b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 720b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 730b57cec5SDimitry Andric #include "llvm/Support/DOTGraphTraits.h" 740b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 750b57cec5SDimitry Andric #include "llvm/Support/GraphWriter.h" 760b57cec5SDimitry Andric #include "llvm/Support/SaveAndRestore.h" 770b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 780b57cec5SDimitry Andric #include <cassert> 790b57cec5SDimitry Andric #include <cstdint> 800b57cec5SDimitry Andric #include <memory> 81bdd1243dSDimitry Andric #include <optional> 820b57cec5SDimitry Andric #include <string> 830b57cec5SDimitry Andric #include <tuple> 840b57cec5SDimitry Andric #include <utility> 850b57cec5SDimitry Andric #include <vector> 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric using namespace clang; 880b57cec5SDimitry Andric using namespace ento; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric #define DEBUG_TYPE "ExprEngine" 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric STATISTIC(NumRemoveDeadBindings, 930b57cec5SDimitry Andric "The # of times RemoveDeadBindings is called"); 940b57cec5SDimitry Andric STATISTIC(NumMaxBlockCountReached, 950b57cec5SDimitry Andric "The # of aborted paths due to reaching the maximum block count in " 960b57cec5SDimitry Andric "a top level function"); 970b57cec5SDimitry Andric STATISTIC(NumMaxBlockCountReachedInInlined, 980b57cec5SDimitry Andric "The # of aborted paths due to reaching the maximum block count in " 990b57cec5SDimitry Andric "an inlined function"); 1000b57cec5SDimitry Andric STATISTIC(NumTimesRetriedWithoutInlining, 1010b57cec5SDimitry Andric "The # of times we re-evaluated a call without inlining"); 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1040b57cec5SDimitry Andric // Internal program state traits. 1050b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric namespace { 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric // When modeling a C++ constructor, for a variety of reasons we need to track 1100b57cec5SDimitry Andric // the location of the object for the duration of its ConstructionContext. 1110b57cec5SDimitry Andric // ObjectsUnderConstruction maps statements within the construction context 1120b57cec5SDimitry Andric // to the object's location, so that on every such statement the location 1130b57cec5SDimitry Andric // could have been retrieved. 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric /// ConstructedObjectKey is used for being able to find the path-sensitive 1160b57cec5SDimitry Andric /// memory region of a freshly constructed object while modeling the AST node 1170b57cec5SDimitry Andric /// that syntactically represents the object that is being constructed. 1180b57cec5SDimitry Andric /// Semantics of such nodes may sometimes require access to the region that's 1190b57cec5SDimitry Andric /// not otherwise present in the program state, or to the very fact that 1200b57cec5SDimitry Andric /// the construction context was present and contained references to these 1210b57cec5SDimitry Andric /// AST nodes. 1220b57cec5SDimitry Andric class ConstructedObjectKey { 12381ad6265SDimitry Andric using ConstructedObjectKeyImpl = 12481ad6265SDimitry Andric std::pair<ConstructionContextItem, const LocationContext *>; 1250b57cec5SDimitry Andric const ConstructedObjectKeyImpl Impl; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric public: 1280b57cec5SDimitry Andric explicit ConstructedObjectKey(const ConstructionContextItem &Item, 1290b57cec5SDimitry Andric const LocationContext *LC) 1300b57cec5SDimitry Andric : Impl(Item, LC) {} 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric const ConstructionContextItem &getItem() const { return Impl.first; } 1330b57cec5SDimitry Andric const LocationContext *getLocationContext() const { return Impl.second; } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric ASTContext &getASTContext() const { 1360b57cec5SDimitry Andric return getLocationContext()->getDecl()->getASTContext(); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric void printJson(llvm::raw_ostream &Out, PrinterHelper *Helper, 1400b57cec5SDimitry Andric PrintingPolicy &PP) const { 1410b57cec5SDimitry Andric const Stmt *S = getItem().getStmtOrNull(); 1420b57cec5SDimitry Andric const CXXCtorInitializer *I = nullptr; 1430b57cec5SDimitry Andric if (!S) 1440b57cec5SDimitry Andric I = getItem().getCXXCtorInitializer(); 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric if (S) 1470b57cec5SDimitry Andric Out << "\"stmt_id\": " << S->getID(getASTContext()); 1480b57cec5SDimitry Andric else 1490b57cec5SDimitry Andric Out << "\"init_id\": " << I->getID(getASTContext()); 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric // Kind 1520b57cec5SDimitry Andric Out << ", \"kind\": \"" << getItem().getKindAsString() 1530b57cec5SDimitry Andric << "\", \"argument_index\": "; 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric if (getItem().getKind() == ConstructionContextItem::ArgumentKind) 1560b57cec5SDimitry Andric Out << getItem().getIndex(); 1570b57cec5SDimitry Andric else 1580b57cec5SDimitry Andric Out << "null"; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric // Pretty-print 1610b57cec5SDimitry Andric Out << ", \"pretty\": "; 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric if (S) { 1640b57cec5SDimitry Andric S->printJson(Out, Helper, PP, /*AddQuotes=*/true); 1650b57cec5SDimitry Andric } else { 166e8d8bef9SDimitry Andric Out << '\"' << I->getAnyMember()->getDeclName() << '\"'; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric void Profile(llvm::FoldingSetNodeID &ID) const { 1710b57cec5SDimitry Andric ID.Add(Impl.first); 1720b57cec5SDimitry Andric ID.AddPointer(Impl.second); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric bool operator==(const ConstructedObjectKey &RHS) const { 1760b57cec5SDimitry Andric return Impl == RHS.Impl; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric bool operator<(const ConstructedObjectKey &RHS) const { 1800b57cec5SDimitry Andric return Impl < RHS.Impl; 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric }; 1830b57cec5SDimitry Andric } // namespace 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric typedef llvm::ImmutableMap<ConstructedObjectKey, SVal> 1860b57cec5SDimitry Andric ObjectsUnderConstructionMap; 1870b57cec5SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction, 1880b57cec5SDimitry Andric ObjectsUnderConstructionMap) 1890b57cec5SDimitry Andric 190fcaf7f86SDimitry Andric // This trait is responsible for storing the index of the element that is to be 191fcaf7f86SDimitry Andric // constructed in the next iteration. As a result a CXXConstructExpr is only 192bdd1243dSDimitry Andric // stored if it is array type. Also the index is the index of the continuous 193fcaf7f86SDimitry Andric // memory region, which is important for multi-dimensional arrays. E.g:: int 194fcaf7f86SDimitry Andric // arr[2][2]; assume arr[1][1] will be the next element under construction, so 195fcaf7f86SDimitry Andric // the index is 3. 196fcaf7f86SDimitry Andric typedef llvm::ImmutableMap< 197fcaf7f86SDimitry Andric std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned> 198fcaf7f86SDimitry Andric IndexOfElementToConstructMap; 199fcaf7f86SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(IndexOfElementToConstruct, 200fcaf7f86SDimitry Andric IndexOfElementToConstructMap) 201972a253aSDimitry Andric 202972a253aSDimitry Andric // This trait is responsible for holding our pending ArrayInitLoopExprs. 203972a253aSDimitry Andric // It pairs the LocationContext and the initializer CXXConstructExpr with 204972a253aSDimitry Andric // the size of the array that's being copy initialized. 205972a253aSDimitry Andric typedef llvm::ImmutableMap< 206972a253aSDimitry Andric std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned> 207972a253aSDimitry Andric PendingInitLoopMap; 208972a253aSDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingInitLoop, PendingInitLoopMap) 209bdd1243dSDimitry Andric 210bdd1243dSDimitry Andric typedef llvm::ImmutableMap<const LocationContext *, unsigned> 211bdd1243dSDimitry Andric PendingArrayDestructionMap; 212bdd1243dSDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingArrayDestruction, 213bdd1243dSDimitry Andric PendingArrayDestructionMap) 214bdd1243dSDimitry Andric 2150b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2160b57cec5SDimitry Andric // Engine construction and deletion. 2170b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric static const char* TagProviderName = "ExprEngine"; 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, 22281ad6265SDimitry Andric AnalysisManager &mgr, SetOfConstDecls *VisitedCalleesIn, 22381ad6265SDimitry Andric FunctionSummariesTy *FS, InliningModes HowToInlineIn) 22481ad6265SDimitry Andric : CTU(CTU), IsCTUEnabled(mgr.getAnalyzerOptions().IsNaiveCTUEnabled), 22581ad6265SDimitry Andric AMgr(mgr), AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()), 2260b57cec5SDimitry Andric Engine(*this, FS, mgr.getAnalyzerOptions()), G(Engine.getGraph()), 2270b57cec5SDimitry Andric StateMgr(getContext(), mgr.getStoreManagerCreator(), 22881ad6265SDimitry Andric mgr.getConstraintManagerCreator(), G.getAllocator(), this), 22981ad6265SDimitry Andric SymMgr(StateMgr.getSymbolManager()), MRMgr(StateMgr.getRegionManager()), 23081ad6265SDimitry Andric svalBuilder(StateMgr.getSValBuilder()), ObjCNoRet(mgr.getASTContext()), 23181ad6265SDimitry Andric BR(mgr, *this), VisitedCallees(VisitedCalleesIn), 23281ad6265SDimitry Andric HowToInline(HowToInlineIn) { 2330b57cec5SDimitry Andric unsigned TrimInterval = mgr.options.GraphTrimInterval; 2340b57cec5SDimitry Andric if (TrimInterval != 0) { 2350b57cec5SDimitry Andric // Enable eager node reclamation when constructing the ExplodedGraph. 2360b57cec5SDimitry Andric G.enableNodeReclamation(TrimInterval); 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2410b57cec5SDimitry Andric // Utility methods. 2420b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { 2450b57cec5SDimitry Andric ProgramStateRef state = StateMgr.getInitialState(InitLoc); 2460b57cec5SDimitry Andric const Decl *D = InitLoc->getDecl(); 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric // Preconditions. 2490b57cec5SDimitry Andric // FIXME: It would be nice if we had a more general mechanism to add 2500b57cec5SDimitry Andric // such preconditions. Some day. 2510b57cec5SDimitry Andric do { 2520b57cec5SDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 2530b57cec5SDimitry Andric // Precondition: the first argument of 'main' is an integer guaranteed 2540b57cec5SDimitry Andric // to be > 0. 2550b57cec5SDimitry Andric const IdentifierInfo *II = FD->getIdentifier(); 2560b57cec5SDimitry Andric if (!II || !(II->getName() == "main" && FD->getNumParams() > 0)) 2570b57cec5SDimitry Andric break; 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric const ParmVarDecl *PD = FD->getParamDecl(0); 2600b57cec5SDimitry Andric QualType T = PD->getType(); 2610b57cec5SDimitry Andric const auto *BT = dyn_cast<BuiltinType>(T); 2620b57cec5SDimitry Andric if (!BT || !BT->isInteger()) 2630b57cec5SDimitry Andric break; 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric const MemRegion *R = state->getRegion(PD, InitLoc); 2660b57cec5SDimitry Andric if (!R) 2670b57cec5SDimitry Andric break; 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric SVal V = state->getSVal(loc::MemRegionVal(R)); 2700b57cec5SDimitry Andric SVal Constraint_untested = evalBinOp(state, BO_GT, V, 2710b57cec5SDimitry Andric svalBuilder.makeZeroVal(T), 2720b57cec5SDimitry Andric svalBuilder.getConditionType()); 2730b57cec5SDimitry Andric 274bdd1243dSDimitry Andric std::optional<DefinedOrUnknownSVal> Constraint = 2750b57cec5SDimitry Andric Constraint_untested.getAs<DefinedOrUnknownSVal>(); 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric if (!Constraint) 2780b57cec5SDimitry Andric break; 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric if (ProgramStateRef newState = state->assume(*Constraint, true)) 2810b57cec5SDimitry Andric state = newState; 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric break; 2840b57cec5SDimitry Andric } 2850b57cec5SDimitry Andric while (false); 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 2880b57cec5SDimitry Andric // Precondition: 'self' is always non-null upon entry to an Objective-C 2890b57cec5SDimitry Andric // method. 2900b57cec5SDimitry Andric const ImplicitParamDecl *SelfD = MD->getSelfDecl(); 2910b57cec5SDimitry Andric const MemRegion *R = state->getRegion(SelfD, InitLoc); 2920b57cec5SDimitry Andric SVal V = state->getSVal(loc::MemRegionVal(R)); 2930b57cec5SDimitry Andric 294bdd1243dSDimitry Andric if (std::optional<Loc> LV = V.getAs<Loc>()) { 2950b57cec5SDimitry Andric // Assume that the pointer value in 'self' is non-null. 2960b57cec5SDimitry Andric state = state->assume(*LV, true); 2970b57cec5SDimitry Andric assert(state && "'self' cannot be null"); 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { 3025f757f3fSDimitry Andric if (MD->isImplicitObjectMemberFunction()) { 3030b57cec5SDimitry Andric // Precondition: 'this' is always non-null upon entry to the 3040b57cec5SDimitry Andric // top-level function. This is our starting assumption for 3050b57cec5SDimitry Andric // analyzing an "open" program. 3060b57cec5SDimitry Andric const StackFrameContext *SFC = InitLoc->getStackFrame(); 3070b57cec5SDimitry Andric if (SFC->getParent() == nullptr) { 3080b57cec5SDimitry Andric loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC); 3090b57cec5SDimitry Andric SVal V = state->getSVal(L); 310bdd1243dSDimitry Andric if (std::optional<Loc> LV = V.getAs<Loc>()) { 3110b57cec5SDimitry Andric state = state->assume(*LV, true); 3120b57cec5SDimitry Andric assert(state && "'this' cannot be null"); 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric return state; 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( 3220b57cec5SDimitry Andric ProgramStateRef State, const LocationContext *LC, 3230b57cec5SDimitry Andric const Expr *InitWithAdjustments, const Expr *Result, 3240b57cec5SDimitry Andric const SubRegion **OutRegionWithAdjustments) { 3250b57cec5SDimitry Andric // FIXME: This function is a hack that works around the quirky AST 3260b57cec5SDimitry Andric // we're often having with respect to C++ temporaries. If only we modelled 3270b57cec5SDimitry Andric // the actual execution order of statements properly in the CFG, 3280b57cec5SDimitry Andric // all the hassle with adjustments would not be necessary, 3290b57cec5SDimitry Andric // and perhaps the whole function would be removed. 3300b57cec5SDimitry Andric SVal InitValWithAdjustments = State->getSVal(InitWithAdjustments, LC); 3310b57cec5SDimitry Andric if (!Result) { 3320b57cec5SDimitry Andric // If we don't have an explicit result expression, we're in "if needed" 3330b57cec5SDimitry Andric // mode. Only create a region if the current value is a NonLoc. 33481ad6265SDimitry Andric if (!isa<NonLoc>(InitValWithAdjustments)) { 3350b57cec5SDimitry Andric if (OutRegionWithAdjustments) 3360b57cec5SDimitry Andric *OutRegionWithAdjustments = nullptr; 3370b57cec5SDimitry Andric return State; 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric Result = InitWithAdjustments; 3400b57cec5SDimitry Andric } else { 3415e801ac6SDimitry Andric // We need to create a region no matter what. Make sure we don't try to 3425e801ac6SDimitry Andric // stuff a Loc into a non-pointer temporary region. 34381ad6265SDimitry Andric assert(!isa<Loc>(InitValWithAdjustments) || 3440b57cec5SDimitry Andric Loc::isLocType(Result->getType()) || 3450b57cec5SDimitry Andric Result->getType()->isMemberPointerType()); 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric ProgramStateManager &StateMgr = State->getStateManager(); 3490b57cec5SDimitry Andric MemRegionManager &MRMgr = StateMgr.getRegionManager(); 3500b57cec5SDimitry Andric StoreManager &StoreMgr = StateMgr.getStoreManager(); 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric // MaterializeTemporaryExpr may appear out of place, after a few field and 3530b57cec5SDimitry Andric // base-class accesses have been made to the object, even though semantically 3540b57cec5SDimitry Andric // it is the whole object that gets materialized and lifetime-extended. 3550b57cec5SDimitry Andric // 3560b57cec5SDimitry Andric // For example: 3570b57cec5SDimitry Andric // 3580b57cec5SDimitry Andric // `-MaterializeTemporaryExpr 3590b57cec5SDimitry Andric // `-MemberExpr 3600b57cec5SDimitry Andric // `-CXXTemporaryObjectExpr 3610b57cec5SDimitry Andric // 3620b57cec5SDimitry Andric // instead of the more natural 3630b57cec5SDimitry Andric // 3640b57cec5SDimitry Andric // `-MemberExpr 3650b57cec5SDimitry Andric // `-MaterializeTemporaryExpr 3660b57cec5SDimitry Andric // `-CXXTemporaryObjectExpr 3670b57cec5SDimitry Andric // 3680b57cec5SDimitry Andric // Use the usual methods for obtaining the expression of the base object, 3690b57cec5SDimitry Andric // and record the adjustments that we need to make to obtain the sub-object 3700b57cec5SDimitry Andric // that the whole expression 'Ex' refers to. This trick is usual, 3710b57cec5SDimitry Andric // in the sense that CodeGen takes a similar route. 3720b57cec5SDimitry Andric 3730b57cec5SDimitry Andric SmallVector<const Expr *, 2> CommaLHSs; 3740b57cec5SDimitry Andric SmallVector<SubobjectAdjustment, 2> Adjustments; 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric const Expr *Init = InitWithAdjustments->skipRValueSubobjectAdjustments( 3770b57cec5SDimitry Andric CommaLHSs, Adjustments); 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric // Take the region for Init, i.e. for the whole object. If we do not remember 3800b57cec5SDimitry Andric // the region in which the object originally was constructed, come up with 3810b57cec5SDimitry Andric // a new temporary region out of thin air and copy the contents of the object 3820b57cec5SDimitry Andric // (which are currently present in the Environment, because Init is an rvalue) 3830b57cec5SDimitry Andric // into that region. This is not correct, but it is better than nothing. 3840b57cec5SDimitry Andric const TypedValueRegion *TR = nullptr; 3850b57cec5SDimitry Andric if (const auto *MT = dyn_cast<MaterializeTemporaryExpr>(Result)) { 386bdd1243dSDimitry Andric if (std::optional<SVal> V = getObjectUnderConstruction(State, MT, LC)) { 3870b57cec5SDimitry Andric State = finishObjectConstruction(State, MT, LC); 3880b57cec5SDimitry Andric State = State->BindExpr(Result, LC, *V); 3890b57cec5SDimitry Andric return State; 39006c3fb27SDimitry Andric } else if (const ValueDecl *VD = MT->getExtendingDecl()) { 3910b57cec5SDimitry Andric StorageDuration SD = MT->getStorageDuration(); 39206c3fb27SDimitry Andric assert(SD != SD_FullExpression); 3930b57cec5SDimitry Andric // If this object is bound to a reference with static storage duration, we 3940b57cec5SDimitry Andric // put it in a different region to prevent "address leakage" warnings. 3950b57cec5SDimitry Andric if (SD == SD_Static || SD == SD_Thread) { 39606c3fb27SDimitry Andric TR = MRMgr.getCXXStaticLifetimeExtendedObjectRegion(Init, VD); 3970b57cec5SDimitry Andric } else { 39806c3fb27SDimitry Andric TR = MRMgr.getCXXLifetimeExtendedObjectRegion(Init, VD, LC); 3990b57cec5SDimitry Andric } 40006c3fb27SDimitry Andric } else { 40106c3fb27SDimitry Andric assert(MT->getStorageDuration() == SD_FullExpression); 40206c3fb27SDimitry Andric TR = MRMgr.getCXXTempObjectRegion(Init, LC); 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric } else { 4050b57cec5SDimitry Andric TR = MRMgr.getCXXTempObjectRegion(Init, LC); 4060b57cec5SDimitry Andric } 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric SVal Reg = loc::MemRegionVal(TR); 4090b57cec5SDimitry Andric SVal BaseReg = Reg; 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric // Make the necessary adjustments to obtain the sub-object. 412349cc55cSDimitry Andric for (const SubobjectAdjustment &Adj : llvm::reverse(Adjustments)) { 4130b57cec5SDimitry Andric switch (Adj.Kind) { 4140b57cec5SDimitry Andric case SubobjectAdjustment::DerivedToBaseAdjustment: 4150b57cec5SDimitry Andric Reg = StoreMgr.evalDerivedToBase(Reg, Adj.DerivedToBase.BasePath); 4160b57cec5SDimitry Andric break; 4170b57cec5SDimitry Andric case SubobjectAdjustment::FieldAdjustment: 4180b57cec5SDimitry Andric Reg = StoreMgr.getLValueField(Adj.Field, Reg); 4190b57cec5SDimitry Andric break; 4200b57cec5SDimitry Andric case SubobjectAdjustment::MemberPointerAdjustment: 4210b57cec5SDimitry Andric // FIXME: Unimplemented. 4220b57cec5SDimitry Andric State = State->invalidateRegions(Reg, InitWithAdjustments, 4230b57cec5SDimitry Andric currBldrCtx->blockCount(), LC, true, 4240b57cec5SDimitry Andric nullptr, nullptr, nullptr); 4250b57cec5SDimitry Andric return State; 4260b57cec5SDimitry Andric } 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric // What remains is to copy the value of the object to the new region. 4300b57cec5SDimitry Andric // FIXME: In other words, what we should always do is copy value of the 4310b57cec5SDimitry Andric // Init expression (which corresponds to the bigger object) to the whole 4320b57cec5SDimitry Andric // temporary region TR. However, this value is often no longer present 4330b57cec5SDimitry Andric // in the Environment. If it has disappeared, we instead invalidate TR. 4340b57cec5SDimitry Andric // Still, what we can do is assign the value of expression Ex (which 4350b57cec5SDimitry Andric // corresponds to the sub-object) to the TR's sub-region Reg. At least, 4360b57cec5SDimitry Andric // values inside Reg would be correct. 4370b57cec5SDimitry Andric SVal InitVal = State->getSVal(Init, LC); 4380b57cec5SDimitry Andric if (InitVal.isUnknown()) { 4390b57cec5SDimitry Andric InitVal = getSValBuilder().conjureSymbolVal(Result, LC, Init->getType(), 4400b57cec5SDimitry Andric currBldrCtx->blockCount()); 4410b57cec5SDimitry Andric State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false); 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric // Then we'd need to take the value that certainly exists and bind it 4440b57cec5SDimitry Andric // over. 4450b57cec5SDimitry Andric if (InitValWithAdjustments.isUnknown()) { 4460b57cec5SDimitry Andric // Try to recover some path sensitivity in case we couldn't 4470b57cec5SDimitry Andric // compute the value. 4480b57cec5SDimitry Andric InitValWithAdjustments = getSValBuilder().conjureSymbolVal( 4490b57cec5SDimitry Andric Result, LC, InitWithAdjustments->getType(), 4500b57cec5SDimitry Andric currBldrCtx->blockCount()); 4510b57cec5SDimitry Andric } 4520b57cec5SDimitry Andric State = 4530b57cec5SDimitry Andric State->bindLoc(Reg.castAs<Loc>(), InitValWithAdjustments, LC, false); 4540b57cec5SDimitry Andric } else { 4550b57cec5SDimitry Andric State = State->bindLoc(BaseReg.castAs<Loc>(), InitVal, LC, false); 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric // The result expression would now point to the correct sub-region of the 4590b57cec5SDimitry Andric // newly created temporary region. Do this last in order to getSVal of Init 4600b57cec5SDimitry Andric // correctly in case (Result == Init). 4610b57cec5SDimitry Andric if (Result->isGLValue()) { 4620b57cec5SDimitry Andric State = State->BindExpr(Result, LC, Reg); 4630b57cec5SDimitry Andric } else { 4640b57cec5SDimitry Andric State = State->BindExpr(Result, LC, InitValWithAdjustments); 4650b57cec5SDimitry Andric } 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric // Notify checkers once for two bindLoc()s. 4680b57cec5SDimitry Andric State = processRegionChange(State, TR, LC); 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric if (OutRegionWithAdjustments) 4710b57cec5SDimitry Andric *OutRegionWithAdjustments = cast<SubRegion>(Reg.getAsRegion()); 4720b57cec5SDimitry Andric return State; 4730b57cec5SDimitry Andric } 4740b57cec5SDimitry Andric 475fcaf7f86SDimitry Andric ProgramStateRef ExprEngine::setIndexOfElementToConstruct( 476fcaf7f86SDimitry Andric ProgramStateRef State, const CXXConstructExpr *E, 477fcaf7f86SDimitry Andric const LocationContext *LCtx, unsigned Idx) { 478fcaf7f86SDimitry Andric auto Key = std::make_pair(E, LCtx->getStackFrame()); 479fcaf7f86SDimitry Andric 480fcaf7f86SDimitry Andric assert(!State->contains<IndexOfElementToConstruct>(Key) || Idx > 0); 481fcaf7f86SDimitry Andric 482fcaf7f86SDimitry Andric return State->set<IndexOfElementToConstruct>(Key, Idx); 483fcaf7f86SDimitry Andric } 484fcaf7f86SDimitry Andric 485bdd1243dSDimitry Andric std::optional<unsigned> 486bdd1243dSDimitry Andric ExprEngine::getPendingInitLoop(ProgramStateRef State, const CXXConstructExpr *E, 487972a253aSDimitry Andric const LocationContext *LCtx) { 488bdd1243dSDimitry Andric const unsigned *V = State->get<PendingInitLoop>({E, LCtx->getStackFrame()}); 489bdd1243dSDimitry Andric return V ? std::make_optional(*V) : std::nullopt; 490972a253aSDimitry Andric } 491972a253aSDimitry Andric 492972a253aSDimitry Andric ProgramStateRef ExprEngine::removePendingInitLoop(ProgramStateRef State, 493972a253aSDimitry Andric const CXXConstructExpr *E, 494972a253aSDimitry Andric const LocationContext *LCtx) { 495972a253aSDimitry Andric auto Key = std::make_pair(E, LCtx->getStackFrame()); 496972a253aSDimitry Andric 497972a253aSDimitry Andric assert(E && State->contains<PendingInitLoop>(Key)); 498972a253aSDimitry Andric return State->remove<PendingInitLoop>(Key); 499972a253aSDimitry Andric } 500972a253aSDimitry Andric 501972a253aSDimitry Andric ProgramStateRef ExprEngine::setPendingInitLoop(ProgramStateRef State, 502972a253aSDimitry Andric const CXXConstructExpr *E, 503972a253aSDimitry Andric const LocationContext *LCtx, 504972a253aSDimitry Andric unsigned Size) { 505972a253aSDimitry Andric auto Key = std::make_pair(E, LCtx->getStackFrame()); 506972a253aSDimitry Andric 507972a253aSDimitry Andric assert(!State->contains<PendingInitLoop>(Key) && Size > 0); 508972a253aSDimitry Andric 509972a253aSDimitry Andric return State->set<PendingInitLoop>(Key, Size); 510972a253aSDimitry Andric } 511972a253aSDimitry Andric 512bdd1243dSDimitry Andric std::optional<unsigned> 513fcaf7f86SDimitry Andric ExprEngine::getIndexOfElementToConstruct(ProgramStateRef State, 514fcaf7f86SDimitry Andric const CXXConstructExpr *E, 515fcaf7f86SDimitry Andric const LocationContext *LCtx) { 516bdd1243dSDimitry Andric const unsigned *V = 517bdd1243dSDimitry Andric State->get<IndexOfElementToConstruct>({E, LCtx->getStackFrame()}); 518bdd1243dSDimitry Andric return V ? std::make_optional(*V) : std::nullopt; 519fcaf7f86SDimitry Andric } 520fcaf7f86SDimitry Andric 521fcaf7f86SDimitry Andric ProgramStateRef 522fcaf7f86SDimitry Andric ExprEngine::removeIndexOfElementToConstruct(ProgramStateRef State, 523fcaf7f86SDimitry Andric const CXXConstructExpr *E, 524fcaf7f86SDimitry Andric const LocationContext *LCtx) { 525fcaf7f86SDimitry Andric auto Key = std::make_pair(E, LCtx->getStackFrame()); 526fcaf7f86SDimitry Andric 527fcaf7f86SDimitry Andric assert(E && State->contains<IndexOfElementToConstruct>(Key)); 528fcaf7f86SDimitry Andric return State->remove<IndexOfElementToConstruct>(Key); 529fcaf7f86SDimitry Andric } 530fcaf7f86SDimitry Andric 531bdd1243dSDimitry Andric std::optional<unsigned> 532bdd1243dSDimitry Andric ExprEngine::getPendingArrayDestruction(ProgramStateRef State, 533bdd1243dSDimitry Andric const LocationContext *LCtx) { 534bdd1243dSDimitry Andric assert(LCtx && "LocationContext shouldn't be null!"); 535bdd1243dSDimitry Andric 536bdd1243dSDimitry Andric const unsigned *V = 537bdd1243dSDimitry Andric State->get<PendingArrayDestruction>(LCtx->getStackFrame()); 538bdd1243dSDimitry Andric return V ? std::make_optional(*V) : std::nullopt; 539bdd1243dSDimitry Andric } 540bdd1243dSDimitry Andric 541bdd1243dSDimitry Andric ProgramStateRef ExprEngine::setPendingArrayDestruction( 542bdd1243dSDimitry Andric ProgramStateRef State, const LocationContext *LCtx, unsigned Idx) { 543bdd1243dSDimitry Andric assert(LCtx && "LocationContext shouldn't be null!"); 544bdd1243dSDimitry Andric 545bdd1243dSDimitry Andric auto Key = LCtx->getStackFrame(); 546bdd1243dSDimitry Andric 547bdd1243dSDimitry Andric return State->set<PendingArrayDestruction>(Key, Idx); 548bdd1243dSDimitry Andric } 549bdd1243dSDimitry Andric 550bdd1243dSDimitry Andric ProgramStateRef 551bdd1243dSDimitry Andric ExprEngine::removePendingArrayDestruction(ProgramStateRef State, 552bdd1243dSDimitry Andric const LocationContext *LCtx) { 553bdd1243dSDimitry Andric assert(LCtx && "LocationContext shouldn't be null!"); 554bdd1243dSDimitry Andric 555bdd1243dSDimitry Andric auto Key = LCtx->getStackFrame(); 556bdd1243dSDimitry Andric 557bdd1243dSDimitry Andric assert(LCtx && State->contains<PendingArrayDestruction>(Key)); 558bdd1243dSDimitry Andric return State->remove<PendingArrayDestruction>(Key); 559bdd1243dSDimitry Andric } 560bdd1243dSDimitry Andric 5610b57cec5SDimitry Andric ProgramStateRef 5620b57cec5SDimitry Andric ExprEngine::addObjectUnderConstruction(ProgramStateRef State, 5630b57cec5SDimitry Andric const ConstructionContextItem &Item, 5640b57cec5SDimitry Andric const LocationContext *LC, SVal V) { 5650b57cec5SDimitry Andric ConstructedObjectKey Key(Item, LC->getStackFrame()); 566fcaf7f86SDimitry Andric 567972a253aSDimitry Andric const Expr *Init = nullptr; 568fcaf7f86SDimitry Andric 569fcaf7f86SDimitry Andric if (auto DS = dyn_cast_or_null<DeclStmt>(Item.getStmtOrNull())) { 570fcaf7f86SDimitry Andric if (auto VD = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) 571972a253aSDimitry Andric Init = VD->getInit(); 572fcaf7f86SDimitry Andric } 573fcaf7f86SDimitry Andric 574972a253aSDimitry Andric if (auto LE = dyn_cast_or_null<LambdaExpr>(Item.getStmtOrNull())) 575972a253aSDimitry Andric Init = *(LE->capture_init_begin() + Item.getIndex()); 576972a253aSDimitry Andric 577972a253aSDimitry Andric if (!Init && !Item.getStmtOrNull()) 578972a253aSDimitry Andric Init = Item.getCXXCtorInitializer()->getInit(); 579972a253aSDimitry Andric 580972a253aSDimitry Andric // In an ArrayInitLoopExpr the real initializer is returned by 581bdd1243dSDimitry Andric // getSubExpr(). Note that AILEs can be nested in case of 582bdd1243dSDimitry Andric // multidimesnional arrays. 583972a253aSDimitry Andric if (const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init)) 584bdd1243dSDimitry Andric Init = extractElementInitializerFromNestedAILE(AILE); 585fcaf7f86SDimitry Andric 5860b57cec5SDimitry Andric // FIXME: Currently the state might already contain the marker due to 5870b57cec5SDimitry Andric // incorrect handling of temporaries bound to default parameters. 588fcaf7f86SDimitry Andric // The state will already contain the marker if we construct elements 589fcaf7f86SDimitry Andric // in an array, as we visit the same statement multiple times before 590fcaf7f86SDimitry Andric // the array declaration. The marker is removed when we exit the 591fcaf7f86SDimitry Andric // constructor call. 592fcaf7f86SDimitry Andric assert((!State->get<ObjectsUnderConstruction>(Key) || 5930b57cec5SDimitry Andric Key.getItem().getKind() == 594fcaf7f86SDimitry Andric ConstructionContextItem::TemporaryDestructorKind || 595972a253aSDimitry Andric State->contains<IndexOfElementToConstruct>( 596972a253aSDimitry Andric {dyn_cast_or_null<CXXConstructExpr>(Init), LC})) && 597fcaf7f86SDimitry Andric "The object is already marked as `UnderConstruction`, when it's not " 598fcaf7f86SDimitry Andric "supposed to!"); 5990b57cec5SDimitry Andric return State->set<ObjectsUnderConstruction>(Key, V); 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric 602bdd1243dSDimitry Andric std::optional<SVal> 6030b57cec5SDimitry Andric ExprEngine::getObjectUnderConstruction(ProgramStateRef State, 6040b57cec5SDimitry Andric const ConstructionContextItem &Item, 6050b57cec5SDimitry Andric const LocationContext *LC) { 6060b57cec5SDimitry Andric ConstructedObjectKey Key(Item, LC->getStackFrame()); 607bdd1243dSDimitry Andric const SVal *V = State->get<ObjectsUnderConstruction>(Key); 608bdd1243dSDimitry Andric return V ? std::make_optional(*V) : std::nullopt; 6090b57cec5SDimitry Andric } 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric ProgramStateRef 6120b57cec5SDimitry Andric ExprEngine::finishObjectConstruction(ProgramStateRef State, 6130b57cec5SDimitry Andric const ConstructionContextItem &Item, 6140b57cec5SDimitry Andric const LocationContext *LC) { 6150b57cec5SDimitry Andric ConstructedObjectKey Key(Item, LC->getStackFrame()); 6160b57cec5SDimitry Andric assert(State->contains<ObjectsUnderConstruction>(Key)); 6170b57cec5SDimitry Andric return State->remove<ObjectsUnderConstruction>(Key); 6180b57cec5SDimitry Andric } 6190b57cec5SDimitry Andric 6200b57cec5SDimitry Andric ProgramStateRef ExprEngine::elideDestructor(ProgramStateRef State, 6210b57cec5SDimitry Andric const CXXBindTemporaryExpr *BTE, 6220b57cec5SDimitry Andric const LocationContext *LC) { 6230b57cec5SDimitry Andric ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC); 6240b57cec5SDimitry Andric // FIXME: Currently the state might already contain the marker due to 6250b57cec5SDimitry Andric // incorrect handling of temporaries bound to default parameters. 6260b57cec5SDimitry Andric return State->set<ObjectsUnderConstruction>(Key, UnknownVal()); 6270b57cec5SDimitry Andric } 6280b57cec5SDimitry Andric 6290b57cec5SDimitry Andric ProgramStateRef 6300b57cec5SDimitry Andric ExprEngine::cleanupElidedDestructor(ProgramStateRef State, 6310b57cec5SDimitry Andric const CXXBindTemporaryExpr *BTE, 6320b57cec5SDimitry Andric const LocationContext *LC) { 6330b57cec5SDimitry Andric ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC); 6340b57cec5SDimitry Andric assert(State->contains<ObjectsUnderConstruction>(Key)); 6350b57cec5SDimitry Andric return State->remove<ObjectsUnderConstruction>(Key); 6360b57cec5SDimitry Andric } 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric bool ExprEngine::isDestructorElided(ProgramStateRef State, 6390b57cec5SDimitry Andric const CXXBindTemporaryExpr *BTE, 6400b57cec5SDimitry Andric const LocationContext *LC) { 6410b57cec5SDimitry Andric ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC); 6420b57cec5SDimitry Andric return State->contains<ObjectsUnderConstruction>(Key); 6430b57cec5SDimitry Andric } 6440b57cec5SDimitry Andric 6450b57cec5SDimitry Andric bool ExprEngine::areAllObjectsFullyConstructed(ProgramStateRef State, 6460b57cec5SDimitry Andric const LocationContext *FromLC, 6470b57cec5SDimitry Andric const LocationContext *ToLC) { 6480b57cec5SDimitry Andric const LocationContext *LC = FromLC; 6490b57cec5SDimitry Andric while (LC != ToLC) { 6500b57cec5SDimitry Andric assert(LC && "ToLC must be a parent of FromLC!"); 6510b57cec5SDimitry Andric for (auto I : State->get<ObjectsUnderConstruction>()) 6520b57cec5SDimitry Andric if (I.first.getLocationContext() == LC) 6530b57cec5SDimitry Andric return false; 6540b57cec5SDimitry Andric 6550b57cec5SDimitry Andric LC = LC->getParent(); 6560b57cec5SDimitry Andric } 6570b57cec5SDimitry Andric return true; 6580b57cec5SDimitry Andric } 6590b57cec5SDimitry Andric 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 6620b57cec5SDimitry Andric // Top-level transfer function logic (Dispatcher). 6630b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric /// evalAssume - Called by ConstraintManager. Used to call checker-specific 6660b57cec5SDimitry Andric /// logic for handling assumptions on symbolic values. 6670b57cec5SDimitry Andric ProgramStateRef ExprEngine::processAssume(ProgramStateRef state, 6680b57cec5SDimitry Andric SVal cond, bool assumption) { 6690b57cec5SDimitry Andric return getCheckerManager().runCheckersForEvalAssume(state, cond, assumption); 6700b57cec5SDimitry Andric } 6710b57cec5SDimitry Andric 6720b57cec5SDimitry Andric ProgramStateRef 6730b57cec5SDimitry Andric ExprEngine::processRegionChanges(ProgramStateRef state, 6740b57cec5SDimitry Andric const InvalidatedSymbols *invalidated, 6750b57cec5SDimitry Andric ArrayRef<const MemRegion *> Explicits, 6760b57cec5SDimitry Andric ArrayRef<const MemRegion *> Regions, 6770b57cec5SDimitry Andric const LocationContext *LCtx, 6780b57cec5SDimitry Andric const CallEvent *Call) { 6790b57cec5SDimitry Andric return getCheckerManager().runCheckersForRegionChanges(state, invalidated, 6800b57cec5SDimitry Andric Explicits, Regions, 6810b57cec5SDimitry Andric LCtx, Call); 6820b57cec5SDimitry Andric } 6830b57cec5SDimitry Andric 6840b57cec5SDimitry Andric static void 6850b57cec5SDimitry Andric printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State, 6860b57cec5SDimitry Andric const char *NL, const LocationContext *LCtx, 6870b57cec5SDimitry Andric unsigned int Space = 0, bool IsDot = false) { 6880b57cec5SDimitry Andric PrintingPolicy PP = 6890b57cec5SDimitry Andric LCtx->getAnalysisDeclContext()->getASTContext().getPrintingPolicy(); 6900b57cec5SDimitry Andric 6910b57cec5SDimitry Andric ++Space; 6920b57cec5SDimitry Andric bool HasItem = false; 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric // Store the last key. 6950b57cec5SDimitry Andric const ConstructedObjectKey *LastKey = nullptr; 6960b57cec5SDimitry Andric for (const auto &I : State->get<ObjectsUnderConstruction>()) { 6970b57cec5SDimitry Andric const ConstructedObjectKey &Key = I.first; 6980b57cec5SDimitry Andric if (Key.getLocationContext() != LCtx) 6990b57cec5SDimitry Andric continue; 7000b57cec5SDimitry Andric 7010b57cec5SDimitry Andric if (!HasItem) { 702bdd1243dSDimitry Andric Out << '[' << NL; 7030b57cec5SDimitry Andric HasItem = true; 7040b57cec5SDimitry Andric } 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric LastKey = &Key; 7070b57cec5SDimitry Andric } 7080b57cec5SDimitry Andric 7090b57cec5SDimitry Andric for (const auto &I : State->get<ObjectsUnderConstruction>()) { 7100b57cec5SDimitry Andric const ConstructedObjectKey &Key = I.first; 7110b57cec5SDimitry Andric SVal Value = I.second; 7120b57cec5SDimitry Andric if (Key.getLocationContext() != LCtx) 7130b57cec5SDimitry Andric continue; 7140b57cec5SDimitry Andric 7150b57cec5SDimitry Andric Indent(Out, Space, IsDot) << "{ "; 7160b57cec5SDimitry Andric Key.printJson(Out, nullptr, PP); 7170b57cec5SDimitry Andric Out << ", \"value\": \"" << Value << "\" }"; 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric if (&Key != LastKey) 7200b57cec5SDimitry Andric Out << ','; 7210b57cec5SDimitry Andric Out << NL; 7220b57cec5SDimitry Andric } 7230b57cec5SDimitry Andric 7240b57cec5SDimitry Andric if (HasItem) 7250b57cec5SDimitry Andric Indent(Out, --Space, IsDot) << ']'; // End of "location_context". 7260b57cec5SDimitry Andric else { 7270b57cec5SDimitry Andric Out << "null "; 7280b57cec5SDimitry Andric } 7290b57cec5SDimitry Andric } 7300b57cec5SDimitry Andric 731fcaf7f86SDimitry Andric static void printIndicesOfElementsToConstructJson( 732fcaf7f86SDimitry Andric raw_ostream &Out, ProgramStateRef State, const char *NL, 733bdd1243dSDimitry Andric const LocationContext *LCtx, unsigned int Space = 0, bool IsDot = false) { 734fcaf7f86SDimitry Andric using KeyT = std::pair<const Expr *, const LocationContext *>; 735fcaf7f86SDimitry Andric 736bdd1243dSDimitry Andric const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext(); 737bdd1243dSDimitry Andric PrintingPolicy PP = Context.getPrintingPolicy(); 738fcaf7f86SDimitry Andric 739fcaf7f86SDimitry Andric ++Space; 740fcaf7f86SDimitry Andric bool HasItem = false; 741fcaf7f86SDimitry Andric 742fcaf7f86SDimitry Andric // Store the last key. 743fcaf7f86SDimitry Andric KeyT LastKey; 744fcaf7f86SDimitry Andric for (const auto &I : State->get<IndexOfElementToConstruct>()) { 745fcaf7f86SDimitry Andric const KeyT &Key = I.first; 746fcaf7f86SDimitry Andric if (Key.second != LCtx) 747fcaf7f86SDimitry Andric continue; 748fcaf7f86SDimitry Andric 749fcaf7f86SDimitry Andric if (!HasItem) { 750bdd1243dSDimitry Andric Out << '[' << NL; 751fcaf7f86SDimitry Andric HasItem = true; 752fcaf7f86SDimitry Andric } 753fcaf7f86SDimitry Andric 754fcaf7f86SDimitry Andric LastKey = Key; 755fcaf7f86SDimitry Andric } 756fcaf7f86SDimitry Andric 757fcaf7f86SDimitry Andric for (const auto &I : State->get<IndexOfElementToConstruct>()) { 758fcaf7f86SDimitry Andric const KeyT &Key = I.first; 759fcaf7f86SDimitry Andric unsigned Value = I.second; 760fcaf7f86SDimitry Andric if (Key.second != LCtx) 761fcaf7f86SDimitry Andric continue; 762fcaf7f86SDimitry Andric 763fcaf7f86SDimitry Andric Indent(Out, Space, IsDot) << "{ "; 764fcaf7f86SDimitry Andric 765fcaf7f86SDimitry Andric // Expr 766fcaf7f86SDimitry Andric const Expr *E = Key.first; 767fcaf7f86SDimitry Andric Out << "\"stmt_id\": " << E->getID(Context); 768fcaf7f86SDimitry Andric 769bdd1243dSDimitry Andric // Kind 770bdd1243dSDimitry Andric Out << ", \"kind\": null"; 771fcaf7f86SDimitry Andric 772fcaf7f86SDimitry Andric // Pretty-print 773fcaf7f86SDimitry Andric Out << ", \"pretty\": "; 774bdd1243dSDimitry Andric Out << "\"" << E->getStmtClassName() << ' ' 775fcaf7f86SDimitry Andric << E->getSourceRange().printToString(Context.getSourceManager()) << " '" 776fcaf7f86SDimitry Andric << QualType::getAsString(E->getType().split(), PP); 777fcaf7f86SDimitry Andric Out << "'\""; 778fcaf7f86SDimitry Andric 779bdd1243dSDimitry Andric Out << ", \"value\": \"Current index: " << Value - 1 << "\" }"; 780fcaf7f86SDimitry Andric 781fcaf7f86SDimitry Andric if (Key != LastKey) 782fcaf7f86SDimitry Andric Out << ','; 783fcaf7f86SDimitry Andric Out << NL; 784fcaf7f86SDimitry Andric } 785fcaf7f86SDimitry Andric 786fcaf7f86SDimitry Andric if (HasItem) 787fcaf7f86SDimitry Andric Indent(Out, --Space, IsDot) << ']'; // End of "location_context". 788fcaf7f86SDimitry Andric else { 789fcaf7f86SDimitry Andric Out << "null "; 790fcaf7f86SDimitry Andric } 791fcaf7f86SDimitry Andric } 792fcaf7f86SDimitry Andric 793bdd1243dSDimitry Andric static void printPendingInitLoopJson(raw_ostream &Out, ProgramStateRef State, 794bdd1243dSDimitry Andric const char *NL, 795bdd1243dSDimitry Andric const LocationContext *LCtx, 796bdd1243dSDimitry Andric unsigned int Space = 0, 797bdd1243dSDimitry Andric bool IsDot = false) { 798bdd1243dSDimitry Andric using KeyT = std::pair<const CXXConstructExpr *, const LocationContext *>; 799bdd1243dSDimitry Andric 800bdd1243dSDimitry Andric const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext(); 801bdd1243dSDimitry Andric PrintingPolicy PP = Context.getPrintingPolicy(); 802bdd1243dSDimitry Andric 803bdd1243dSDimitry Andric ++Space; 804bdd1243dSDimitry Andric bool HasItem = false; 805bdd1243dSDimitry Andric 806bdd1243dSDimitry Andric // Store the last key. 807bdd1243dSDimitry Andric KeyT LastKey; 808bdd1243dSDimitry Andric for (const auto &I : State->get<PendingInitLoop>()) { 809bdd1243dSDimitry Andric const KeyT &Key = I.first; 810bdd1243dSDimitry Andric if (Key.second != LCtx) 811bdd1243dSDimitry Andric continue; 812bdd1243dSDimitry Andric 813bdd1243dSDimitry Andric if (!HasItem) { 814bdd1243dSDimitry Andric Out << '[' << NL; 815bdd1243dSDimitry Andric HasItem = true; 816bdd1243dSDimitry Andric } 817bdd1243dSDimitry Andric 818bdd1243dSDimitry Andric LastKey = Key; 819bdd1243dSDimitry Andric } 820bdd1243dSDimitry Andric 821bdd1243dSDimitry Andric for (const auto &I : State->get<PendingInitLoop>()) { 822bdd1243dSDimitry Andric const KeyT &Key = I.first; 823bdd1243dSDimitry Andric unsigned Value = I.second; 824bdd1243dSDimitry Andric if (Key.second != LCtx) 825bdd1243dSDimitry Andric continue; 826bdd1243dSDimitry Andric 827bdd1243dSDimitry Andric Indent(Out, Space, IsDot) << "{ "; 828bdd1243dSDimitry Andric 829bdd1243dSDimitry Andric const CXXConstructExpr *E = Key.first; 830bdd1243dSDimitry Andric Out << "\"stmt_id\": " << E->getID(Context); 831bdd1243dSDimitry Andric 832bdd1243dSDimitry Andric Out << ", \"kind\": null"; 833bdd1243dSDimitry Andric Out << ", \"pretty\": "; 834bdd1243dSDimitry Andric Out << '\"' << E->getStmtClassName() << ' ' 835bdd1243dSDimitry Andric << E->getSourceRange().printToString(Context.getSourceManager()) << " '" 836bdd1243dSDimitry Andric << QualType::getAsString(E->getType().split(), PP); 837bdd1243dSDimitry Andric Out << "'\""; 838bdd1243dSDimitry Andric 839bdd1243dSDimitry Andric Out << ", \"value\": \"Flattened size: " << Value << "\"}"; 840bdd1243dSDimitry Andric 841bdd1243dSDimitry Andric if (Key != LastKey) 842bdd1243dSDimitry Andric Out << ','; 843bdd1243dSDimitry Andric Out << NL; 844bdd1243dSDimitry Andric } 845bdd1243dSDimitry Andric 846bdd1243dSDimitry Andric if (HasItem) 847bdd1243dSDimitry Andric Indent(Out, --Space, IsDot) << ']'; // End of "location_context". 848bdd1243dSDimitry Andric else { 849bdd1243dSDimitry Andric Out << "null "; 850bdd1243dSDimitry Andric } 851bdd1243dSDimitry Andric } 852bdd1243dSDimitry Andric 853bdd1243dSDimitry Andric static void 854bdd1243dSDimitry Andric printPendingArrayDestructionsJson(raw_ostream &Out, ProgramStateRef State, 855bdd1243dSDimitry Andric const char *NL, const LocationContext *LCtx, 856bdd1243dSDimitry Andric unsigned int Space = 0, bool IsDot = false) { 857bdd1243dSDimitry Andric using KeyT = const LocationContext *; 858bdd1243dSDimitry Andric 859bdd1243dSDimitry Andric ++Space; 860bdd1243dSDimitry Andric bool HasItem = false; 861bdd1243dSDimitry Andric 862bdd1243dSDimitry Andric // Store the last key. 863bdd1243dSDimitry Andric KeyT LastKey = nullptr; 864bdd1243dSDimitry Andric for (const auto &I : State->get<PendingArrayDestruction>()) { 865bdd1243dSDimitry Andric const KeyT &Key = I.first; 866bdd1243dSDimitry Andric if (Key != LCtx) 867bdd1243dSDimitry Andric continue; 868bdd1243dSDimitry Andric 869bdd1243dSDimitry Andric if (!HasItem) { 870bdd1243dSDimitry Andric Out << '[' << NL; 871bdd1243dSDimitry Andric HasItem = true; 872bdd1243dSDimitry Andric } 873bdd1243dSDimitry Andric 874bdd1243dSDimitry Andric LastKey = Key; 875bdd1243dSDimitry Andric } 876bdd1243dSDimitry Andric 877bdd1243dSDimitry Andric for (const auto &I : State->get<PendingArrayDestruction>()) { 878bdd1243dSDimitry Andric const KeyT &Key = I.first; 879bdd1243dSDimitry Andric if (Key != LCtx) 880bdd1243dSDimitry Andric continue; 881bdd1243dSDimitry Andric 882bdd1243dSDimitry Andric Indent(Out, Space, IsDot) << "{ "; 883bdd1243dSDimitry Andric 884bdd1243dSDimitry Andric Out << "\"stmt_id\": null"; 885bdd1243dSDimitry Andric Out << ", \"kind\": null"; 886bdd1243dSDimitry Andric Out << ", \"pretty\": \"Current index: \""; 887bdd1243dSDimitry Andric Out << ", \"value\": \"" << I.second << "\" }"; 888bdd1243dSDimitry Andric 889bdd1243dSDimitry Andric if (Key != LastKey) 890bdd1243dSDimitry Andric Out << ','; 891bdd1243dSDimitry Andric Out << NL; 892bdd1243dSDimitry Andric } 893bdd1243dSDimitry Andric 894bdd1243dSDimitry Andric if (HasItem) 895bdd1243dSDimitry Andric Indent(Out, --Space, IsDot) << ']'; // End of "location_context". 896bdd1243dSDimitry Andric else { 897bdd1243dSDimitry Andric Out << "null "; 898bdd1243dSDimitry Andric } 899bdd1243dSDimitry Andric } 900bdd1243dSDimitry Andric 901bdd1243dSDimitry Andric /// A helper function to generalize program state trait printing. 902bdd1243dSDimitry Andric /// The function invokes Printer as 'Printer(Out, State, NL, LC, Space, IsDot, 903bdd1243dSDimitry Andric /// std::forward<Args>(args)...)'. \n One possible type for Printer is 904bdd1243dSDimitry Andric /// 'void()(raw_ostream &, ProgramStateRef, const char *, const LocationContext 905bdd1243dSDimitry Andric /// *, unsigned int, bool, ...)' \n \param Trait The state trait to be printed. 906bdd1243dSDimitry Andric /// \param Printer A void function that prints Trait. 907bdd1243dSDimitry Andric /// \param Args An additional parameter pack that is passed to Print upon 908bdd1243dSDimitry Andric /// invocation. 909bdd1243dSDimitry Andric template <typename Trait, typename Printer, typename... Args> 910bdd1243dSDimitry Andric static void printStateTraitWithLocationContextJson( 911bdd1243dSDimitry Andric raw_ostream &Out, ProgramStateRef State, const LocationContext *LCtx, 912bdd1243dSDimitry Andric const char *NL, unsigned int Space, bool IsDot, 913bdd1243dSDimitry Andric const char *jsonPropertyName, Printer printer, Args &&...args) { 914bdd1243dSDimitry Andric 915bdd1243dSDimitry Andric using RequiredType = 916bdd1243dSDimitry Andric void (*)(raw_ostream &, ProgramStateRef, const char *, 917bdd1243dSDimitry Andric const LocationContext *, unsigned int, bool, Args &&...); 918bdd1243dSDimitry Andric 919bdd1243dSDimitry Andric // Try to do as much compile time checking as possible. 920bdd1243dSDimitry Andric // FIXME: check for invocable instead of function? 921bdd1243dSDimitry Andric static_assert(std::is_function_v<std::remove_pointer_t<Printer>>, 922bdd1243dSDimitry Andric "Printer is not a function!"); 923bdd1243dSDimitry Andric static_assert(std::is_convertible_v<Printer, RequiredType>, 924bdd1243dSDimitry Andric "Printer doesn't have the required type!"); 925bdd1243dSDimitry Andric 926bdd1243dSDimitry Andric if (LCtx && !State->get<Trait>().isEmpty()) { 927bdd1243dSDimitry Andric Indent(Out, Space, IsDot) << '\"' << jsonPropertyName << "\": "; 928bdd1243dSDimitry Andric ++Space; 929bdd1243dSDimitry Andric Out << '[' << NL; 930bdd1243dSDimitry Andric LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) { 931bdd1243dSDimitry Andric printer(Out, State, NL, LC, Space, IsDot, std::forward<Args>(args)...); 932bdd1243dSDimitry Andric }); 933bdd1243dSDimitry Andric 934bdd1243dSDimitry Andric --Space; 935bdd1243dSDimitry Andric Indent(Out, Space, IsDot) << "]," << NL; // End of "jsonPropertyName". 936bdd1243dSDimitry Andric } 937bdd1243dSDimitry Andric } 938bdd1243dSDimitry Andric 9390b57cec5SDimitry Andric void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State, 9400b57cec5SDimitry Andric const LocationContext *LCtx, const char *NL, 9410b57cec5SDimitry Andric unsigned int Space, bool IsDot) const { 9420b57cec5SDimitry Andric 943bdd1243dSDimitry Andric printStateTraitWithLocationContextJson<ObjectsUnderConstruction>( 944bdd1243dSDimitry Andric Out, State, LCtx, NL, Space, IsDot, "constructing_objects", 945bdd1243dSDimitry Andric printObjectsUnderConstructionJson); 946bdd1243dSDimitry Andric printStateTraitWithLocationContextJson<IndexOfElementToConstruct>( 947bdd1243dSDimitry Andric Out, State, LCtx, NL, Space, IsDot, "index_of_element", 948bdd1243dSDimitry Andric printIndicesOfElementsToConstructJson); 949bdd1243dSDimitry Andric printStateTraitWithLocationContextJson<PendingInitLoop>( 950bdd1243dSDimitry Andric Out, State, LCtx, NL, Space, IsDot, "pending_init_loops", 951bdd1243dSDimitry Andric printPendingInitLoopJson); 952bdd1243dSDimitry Andric printStateTraitWithLocationContextJson<PendingArrayDestruction>( 953bdd1243dSDimitry Andric Out, State, LCtx, NL, Space, IsDot, "pending_destructors", 954bdd1243dSDimitry Andric printPendingArrayDestructionsJson); 955fcaf7f86SDimitry Andric 9560b57cec5SDimitry Andric getCheckerManager().runCheckersForPrintStateJson(Out, State, NL, Space, 9570b57cec5SDimitry Andric IsDot); 9580b57cec5SDimitry Andric } 9590b57cec5SDimitry Andric 9600b57cec5SDimitry Andric void ExprEngine::processEndWorklist() { 96181ad6265SDimitry Andric // This prints the name of the top-level function if we crash. 96281ad6265SDimitry Andric PrettyStackTraceLocationContext CrashInfo(getRootLocationContext()); 9630b57cec5SDimitry Andric getCheckerManager().runCheckersForEndAnalysis(G, BR, *this); 9640b57cec5SDimitry Andric } 9650b57cec5SDimitry Andric 9660b57cec5SDimitry Andric void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, 9670b57cec5SDimitry Andric unsigned StmtIdx, NodeBuilderContext *Ctx) { 9680b57cec5SDimitry Andric PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); 9690b57cec5SDimitry Andric currStmtIdx = StmtIdx; 9700b57cec5SDimitry Andric currBldrCtx = Ctx; 9710b57cec5SDimitry Andric 9720b57cec5SDimitry Andric switch (E.getKind()) { 9730b57cec5SDimitry Andric case CFGElement::Statement: 9740b57cec5SDimitry Andric case CFGElement::Constructor: 9750b57cec5SDimitry Andric case CFGElement::CXXRecordTypedCall: 9760b57cec5SDimitry Andric ProcessStmt(E.castAs<CFGStmt>().getStmt(), Pred); 9770b57cec5SDimitry Andric return; 9780b57cec5SDimitry Andric case CFGElement::Initializer: 9790b57cec5SDimitry Andric ProcessInitializer(E.castAs<CFGInitializer>(), Pred); 9800b57cec5SDimitry Andric return; 9810b57cec5SDimitry Andric case CFGElement::NewAllocator: 9820b57cec5SDimitry Andric ProcessNewAllocator(E.castAs<CFGNewAllocator>().getAllocatorExpr(), 9830b57cec5SDimitry Andric Pred); 9840b57cec5SDimitry Andric return; 9850b57cec5SDimitry Andric case CFGElement::AutomaticObjectDtor: 9860b57cec5SDimitry Andric case CFGElement::DeleteDtor: 9870b57cec5SDimitry Andric case CFGElement::BaseDtor: 9880b57cec5SDimitry Andric case CFGElement::MemberDtor: 9890b57cec5SDimitry Andric case CFGElement::TemporaryDtor: 9900b57cec5SDimitry Andric ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred); 9910b57cec5SDimitry Andric return; 9920b57cec5SDimitry Andric case CFGElement::LoopExit: 9930b57cec5SDimitry Andric ProcessLoopExit(E.castAs<CFGLoopExit>().getLoopStmt(), Pred); 9940b57cec5SDimitry Andric return; 9950b57cec5SDimitry Andric case CFGElement::LifetimeEnds: 9965f757f3fSDimitry Andric case CFGElement::CleanupFunction: 9970b57cec5SDimitry Andric case CFGElement::ScopeBegin: 9980b57cec5SDimitry Andric case CFGElement::ScopeEnd: 9990b57cec5SDimitry Andric return; 10000b57cec5SDimitry Andric } 10010b57cec5SDimitry Andric } 10020b57cec5SDimitry Andric 10030b57cec5SDimitry Andric static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, 10040b57cec5SDimitry Andric const Stmt *S, 10050b57cec5SDimitry Andric const ExplodedNode *Pred, 10060b57cec5SDimitry Andric const LocationContext *LC) { 10070b57cec5SDimitry Andric // Are we never purging state values? 10080b57cec5SDimitry Andric if (AMgr.options.AnalysisPurgeOpt == PurgeNone) 10090b57cec5SDimitry Andric return false; 10100b57cec5SDimitry Andric 10110b57cec5SDimitry Andric // Is this the beginning of a basic block? 10120b57cec5SDimitry Andric if (Pred->getLocation().getAs<BlockEntrance>()) 10130b57cec5SDimitry Andric return true; 10140b57cec5SDimitry Andric 10150b57cec5SDimitry Andric // Is this on a non-expression? 10160b57cec5SDimitry Andric if (!isa<Expr>(S)) 10170b57cec5SDimitry Andric return true; 10180b57cec5SDimitry Andric 10190b57cec5SDimitry Andric // Run before processing a call. 10200b57cec5SDimitry Andric if (CallEvent::isCallStmt(S)) 10210b57cec5SDimitry Andric return true; 10220b57cec5SDimitry Andric 10230b57cec5SDimitry Andric // Is this an expression that is consumed by another expression? If so, 10240b57cec5SDimitry Andric // postpone cleaning out the state. 10250b57cec5SDimitry Andric ParentMap &PM = LC->getAnalysisDeclContext()->getParentMap(); 10260b57cec5SDimitry Andric return !PM.isConsumedExpr(cast<Expr>(S)); 10270b57cec5SDimitry Andric } 10280b57cec5SDimitry Andric 10290b57cec5SDimitry Andric void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, 10300b57cec5SDimitry Andric const Stmt *ReferenceStmt, 10310b57cec5SDimitry Andric const LocationContext *LC, 10320b57cec5SDimitry Andric const Stmt *DiagnosticStmt, 10330b57cec5SDimitry Andric ProgramPoint::Kind K) { 10340b57cec5SDimitry Andric assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind || 10350b57cec5SDimitry Andric ReferenceStmt == nullptr || isa<ReturnStmt>(ReferenceStmt)) 10360b57cec5SDimitry Andric && "PostStmt is not generally supported by the SymbolReaper yet"); 10370b57cec5SDimitry Andric assert(LC && "Must pass the current (or expiring) LocationContext"); 10380b57cec5SDimitry Andric 10390b57cec5SDimitry Andric if (!DiagnosticStmt) { 10400b57cec5SDimitry Andric DiagnosticStmt = ReferenceStmt; 10410b57cec5SDimitry Andric assert(DiagnosticStmt && "Required for clearing a LocationContext"); 10420b57cec5SDimitry Andric } 10430b57cec5SDimitry Andric 10440b57cec5SDimitry Andric NumRemoveDeadBindings++; 10450b57cec5SDimitry Andric ProgramStateRef CleanedState = Pred->getState(); 10460b57cec5SDimitry Andric 10470b57cec5SDimitry Andric // LC is the location context being destroyed, but SymbolReaper wants a 10480b57cec5SDimitry Andric // location context that is still live. (If this is the top-level stack 10490b57cec5SDimitry Andric // frame, this will be null.) 10500b57cec5SDimitry Andric if (!ReferenceStmt) { 10510b57cec5SDimitry Andric assert(K == ProgramPoint::PostStmtPurgeDeadSymbolsKind && 10520b57cec5SDimitry Andric "Use PostStmtPurgeDeadSymbolsKind for clearing a LocationContext"); 10530b57cec5SDimitry Andric LC = LC->getParent(); 10540b57cec5SDimitry Andric } 10550b57cec5SDimitry Andric 10560b57cec5SDimitry Andric const StackFrameContext *SFC = LC ? LC->getStackFrame() : nullptr; 10570b57cec5SDimitry Andric SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager()); 10580b57cec5SDimitry Andric 10590b57cec5SDimitry Andric for (auto I : CleanedState->get<ObjectsUnderConstruction>()) { 10600b57cec5SDimitry Andric if (SymbolRef Sym = I.second.getAsSymbol()) 10610b57cec5SDimitry Andric SymReaper.markLive(Sym); 10620b57cec5SDimitry Andric if (const MemRegion *MR = I.second.getAsRegion()) 10630b57cec5SDimitry Andric SymReaper.markLive(MR); 10640b57cec5SDimitry Andric } 10650b57cec5SDimitry Andric 10660b57cec5SDimitry Andric getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper); 10670b57cec5SDimitry Andric 10680b57cec5SDimitry Andric // Create a state in which dead bindings are removed from the environment 10690b57cec5SDimitry Andric // and the store. TODO: The function should just return new env and store, 10700b57cec5SDimitry Andric // not a new state. 1071480093f4SDimitry Andric CleanedState = StateMgr.removeDeadBindingsFromEnvironmentAndStore( 1072480093f4SDimitry Andric CleanedState, SFC, SymReaper); 10730b57cec5SDimitry Andric 10740b57cec5SDimitry Andric // Process any special transfer function for dead symbols. 10750b57cec5SDimitry Andric // A tag to track convenience transitions, which can be removed at cleanup. 10760b57cec5SDimitry Andric static SimpleProgramPointTag cleanupTag(TagProviderName, "Clean Node"); 10770b57cec5SDimitry Andric // Call checkers with the non-cleaned state so that they could query the 10780b57cec5SDimitry Andric // values of the soon to be dead symbols. 10790b57cec5SDimitry Andric ExplodedNodeSet CheckedSet; 10800b57cec5SDimitry Andric getCheckerManager().runCheckersForDeadSymbols(CheckedSet, Pred, SymReaper, 10810b57cec5SDimitry Andric DiagnosticStmt, *this, K); 10820b57cec5SDimitry Andric 10830b57cec5SDimitry Andric // For each node in CheckedSet, generate CleanedNodes that have the 10840b57cec5SDimitry Andric // environment, the store, and the constraints cleaned up but have the 10850b57cec5SDimitry Andric // user-supplied states as the predecessors. 10860b57cec5SDimitry Andric StmtNodeBuilder Bldr(CheckedSet, Out, *currBldrCtx); 10870b57cec5SDimitry Andric for (const auto I : CheckedSet) { 10880b57cec5SDimitry Andric ProgramStateRef CheckerState = I->getState(); 10890b57cec5SDimitry Andric 10900b57cec5SDimitry Andric // The constraint manager has not been cleaned up yet, so clean up now. 10910b57cec5SDimitry Andric CheckerState = 10920b57cec5SDimitry Andric getConstraintManager().removeDeadBindings(CheckerState, SymReaper); 10930b57cec5SDimitry Andric 10940b57cec5SDimitry Andric assert(StateMgr.haveEqualEnvironments(CheckerState, Pred->getState()) && 10950b57cec5SDimitry Andric "Checkers are not allowed to modify the Environment as a part of " 10960b57cec5SDimitry Andric "checkDeadSymbols processing."); 10970b57cec5SDimitry Andric assert(StateMgr.haveEqualStores(CheckerState, Pred->getState()) && 10980b57cec5SDimitry Andric "Checkers are not allowed to modify the Store as a part of " 10990b57cec5SDimitry Andric "checkDeadSymbols processing."); 11000b57cec5SDimitry Andric 11010b57cec5SDimitry Andric // Create a state based on CleanedState with CheckerState GDM and 11020b57cec5SDimitry Andric // generate a transition to that state. 11030b57cec5SDimitry Andric ProgramStateRef CleanedCheckerSt = 11040b57cec5SDimitry Andric StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState); 11050b57cec5SDimitry Andric Bldr.generateNode(DiagnosticStmt, I, CleanedCheckerSt, &cleanupTag, K); 11060b57cec5SDimitry Andric } 11070b57cec5SDimitry Andric } 11080b57cec5SDimitry Andric 11090b57cec5SDimitry Andric void ExprEngine::ProcessStmt(const Stmt *currStmt, ExplodedNode *Pred) { 11100b57cec5SDimitry Andric // Reclaim any unnecessary nodes in the ExplodedGraph. 11110b57cec5SDimitry Andric G.reclaimRecentlyAllocatedNodes(); 11120b57cec5SDimitry Andric 11130b57cec5SDimitry Andric PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), 11140b57cec5SDimitry Andric currStmt->getBeginLoc(), 11150b57cec5SDimitry Andric "Error evaluating statement"); 11160b57cec5SDimitry Andric 11170b57cec5SDimitry Andric // Remove dead bindings and symbols. 11180b57cec5SDimitry Andric ExplodedNodeSet CleanedStates; 11190b57cec5SDimitry Andric if (shouldRemoveDeadBindings(AMgr, currStmt, Pred, 11200b57cec5SDimitry Andric Pred->getLocationContext())) { 11210b57cec5SDimitry Andric removeDead(Pred, CleanedStates, currStmt, 11220b57cec5SDimitry Andric Pred->getLocationContext()); 11230b57cec5SDimitry Andric } else 11240b57cec5SDimitry Andric CleanedStates.Add(Pred); 11250b57cec5SDimitry Andric 11260b57cec5SDimitry Andric // Visit the statement. 11270b57cec5SDimitry Andric ExplodedNodeSet Dst; 11280b57cec5SDimitry Andric for (const auto I : CleanedStates) { 11290b57cec5SDimitry Andric ExplodedNodeSet DstI; 11300b57cec5SDimitry Andric // Visit the statement. 11310b57cec5SDimitry Andric Visit(currStmt, I, DstI); 11320b57cec5SDimitry Andric Dst.insert(DstI); 11330b57cec5SDimitry Andric } 11340b57cec5SDimitry Andric 11350b57cec5SDimitry Andric // Enqueue the new nodes onto the work list. 11360b57cec5SDimitry Andric Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); 11370b57cec5SDimitry Andric } 11380b57cec5SDimitry Andric 11390b57cec5SDimitry Andric void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) { 11400b57cec5SDimitry Andric PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), 11410b57cec5SDimitry Andric S->getBeginLoc(), 11420b57cec5SDimitry Andric "Error evaluating end of the loop"); 11430b57cec5SDimitry Andric ExplodedNodeSet Dst; 11440b57cec5SDimitry Andric Dst.Add(Pred); 11450b57cec5SDimitry Andric NodeBuilder Bldr(Pred, Dst, *currBldrCtx); 11460b57cec5SDimitry Andric ProgramStateRef NewState = Pred->getState(); 11470b57cec5SDimitry Andric 11480b57cec5SDimitry Andric if(AMgr.options.ShouldUnrollLoops) 11490b57cec5SDimitry Andric NewState = processLoopEnd(S, NewState); 11500b57cec5SDimitry Andric 11510b57cec5SDimitry Andric LoopExit PP(S, Pred->getLocationContext()); 11520b57cec5SDimitry Andric Bldr.generateNode(PP, NewState, Pred); 11530b57cec5SDimitry Andric // Enqueue the new nodes onto the work list. 11540b57cec5SDimitry Andric Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); 11550b57cec5SDimitry Andric } 11560b57cec5SDimitry Andric 11570b57cec5SDimitry Andric void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit, 11580b57cec5SDimitry Andric ExplodedNode *Pred) { 11590b57cec5SDimitry Andric const CXXCtorInitializer *BMI = CFGInit.getInitializer(); 11600b57cec5SDimitry Andric const Expr *Init = BMI->getInit()->IgnoreImplicit(); 11610b57cec5SDimitry Andric const LocationContext *LC = Pred->getLocationContext(); 11620b57cec5SDimitry Andric 11630b57cec5SDimitry Andric PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), 11640b57cec5SDimitry Andric BMI->getSourceLocation(), 11650b57cec5SDimitry Andric "Error evaluating initializer"); 11660b57cec5SDimitry Andric 11670b57cec5SDimitry Andric // We don't clean up dead bindings here. 11680b57cec5SDimitry Andric const auto *stackFrame = cast<StackFrameContext>(Pred->getLocationContext()); 11690b57cec5SDimitry Andric const auto *decl = cast<CXXConstructorDecl>(stackFrame->getDecl()); 11700b57cec5SDimitry Andric 11710b57cec5SDimitry Andric ProgramStateRef State = Pred->getState(); 11720b57cec5SDimitry Andric SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame)); 11730b57cec5SDimitry Andric 11740b57cec5SDimitry Andric ExplodedNodeSet Tmp; 11750b57cec5SDimitry Andric SVal FieldLoc; 11760b57cec5SDimitry Andric 11770b57cec5SDimitry Andric // Evaluate the initializer, if necessary 11780b57cec5SDimitry Andric if (BMI->isAnyMemberInitializer()) { 11790b57cec5SDimitry Andric // Constructors build the object directly in the field, 11800b57cec5SDimitry Andric // but non-objects must be copied in from the initializer. 11810b57cec5SDimitry Andric if (getObjectUnderConstruction(State, BMI, LC)) { 11820b57cec5SDimitry Andric // The field was directly constructed, so there is no need to bind. 11830b57cec5SDimitry Andric // But we still need to stop tracking the object under construction. 11840b57cec5SDimitry Andric State = finishObjectConstruction(State, BMI, LC); 11850b57cec5SDimitry Andric NodeBuilder Bldr(Pred, Tmp, *currBldrCtx); 11860b57cec5SDimitry Andric PostStore PS(Init, LC, /*Loc*/ nullptr, /*tag*/ nullptr); 11870b57cec5SDimitry Andric Bldr.generateNode(PS, State, Pred); 11880b57cec5SDimitry Andric } else { 11890b57cec5SDimitry Andric const ValueDecl *Field; 11900b57cec5SDimitry Andric if (BMI->isIndirectMemberInitializer()) { 11910b57cec5SDimitry Andric Field = BMI->getIndirectMember(); 11920b57cec5SDimitry Andric FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal); 11930b57cec5SDimitry Andric } else { 11940b57cec5SDimitry Andric Field = BMI->getMember(); 11950b57cec5SDimitry Andric FieldLoc = State->getLValue(BMI->getMember(), thisVal); 11960b57cec5SDimitry Andric } 11970b57cec5SDimitry Andric 11980b57cec5SDimitry Andric SVal InitVal; 11990b57cec5SDimitry Andric if (Init->getType()->isArrayType()) { 12000b57cec5SDimitry Andric // Handle arrays of trivial type. We can represent this with a 12010b57cec5SDimitry Andric // primitive load/copy from the base array region. 12020b57cec5SDimitry Andric const ArraySubscriptExpr *ASE; 12030b57cec5SDimitry Andric while ((ASE = dyn_cast<ArraySubscriptExpr>(Init))) 12040b57cec5SDimitry Andric Init = ASE->getBase()->IgnoreImplicit(); 12050b57cec5SDimitry Andric 12060b57cec5SDimitry Andric SVal LValue = State->getSVal(Init, stackFrame); 12070b57cec5SDimitry Andric if (!Field->getType()->isReferenceType()) 1208bdd1243dSDimitry Andric if (std::optional<Loc> LValueLoc = LValue.getAs<Loc>()) 12090b57cec5SDimitry Andric InitVal = State->getSVal(*LValueLoc); 12100b57cec5SDimitry Andric 12110b57cec5SDimitry Andric // If we fail to get the value for some reason, use a symbolic value. 12120b57cec5SDimitry Andric if (InitVal.isUnknownOrUndef()) { 12130b57cec5SDimitry Andric SValBuilder &SVB = getSValBuilder(); 12140b57cec5SDimitry Andric InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame, 12150b57cec5SDimitry Andric Field->getType(), 12160b57cec5SDimitry Andric currBldrCtx->blockCount()); 12170b57cec5SDimitry Andric } 12180b57cec5SDimitry Andric } else { 12190b57cec5SDimitry Andric InitVal = State->getSVal(BMI->getInit(), stackFrame); 12200b57cec5SDimitry Andric } 12210b57cec5SDimitry Andric 12220b57cec5SDimitry Andric PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); 12230b57cec5SDimitry Andric evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP); 12240b57cec5SDimitry Andric } 12255f757f3fSDimitry Andric } else if (BMI->isBaseInitializer() && isa<InitListExpr>(Init)) { 12265f757f3fSDimitry Andric // When the base class is initialized with an initialization list and the 12275f757f3fSDimitry Andric // base class does not have a ctor, there will not be a CXXConstructExpr to 12285f757f3fSDimitry Andric // initialize the base region. Hence, we need to make the bind for it. 12295f757f3fSDimitry Andric SVal BaseLoc = getStoreManager().evalDerivedToBase( 12305f757f3fSDimitry Andric thisVal, QualType(BMI->getBaseClass(), 0), BMI->isBaseVirtual()); 12315f757f3fSDimitry Andric SVal InitVal = State->getSVal(Init, stackFrame); 12325f757f3fSDimitry Andric evalBind(Tmp, Init, Pred, BaseLoc, InitVal, /*isInit=*/true); 12330b57cec5SDimitry Andric } else { 12340b57cec5SDimitry Andric assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer()); 12350b57cec5SDimitry Andric Tmp.insert(Pred); 12360b57cec5SDimitry Andric // We already did all the work when visiting the CXXConstructExpr. 12370b57cec5SDimitry Andric } 12380b57cec5SDimitry Andric 12390b57cec5SDimitry Andric // Construct PostInitializer nodes whether the state changed or not, 12400b57cec5SDimitry Andric // so that the diagnostics don't get confused. 12410b57cec5SDimitry Andric PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); 12420b57cec5SDimitry Andric ExplodedNodeSet Dst; 12430b57cec5SDimitry Andric NodeBuilder Bldr(Tmp, Dst, *currBldrCtx); 12440b57cec5SDimitry Andric for (const auto I : Tmp) { 12450b57cec5SDimitry Andric ProgramStateRef State = I->getState(); 12460b57cec5SDimitry Andric Bldr.generateNode(PP, State, I); 12470b57cec5SDimitry Andric } 12480b57cec5SDimitry Andric 12490b57cec5SDimitry Andric // Enqueue the new nodes onto the work list. 12500b57cec5SDimitry Andric Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); 12510b57cec5SDimitry Andric } 12520b57cec5SDimitry Andric 1253bdd1243dSDimitry Andric std::pair<ProgramStateRef, uint64_t> 1254bdd1243dSDimitry Andric ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State, 1255bdd1243dSDimitry Andric const MemRegion *Region, 1256bdd1243dSDimitry Andric const QualType &ElementTy, 1257bdd1243dSDimitry Andric const LocationContext *LCtx, 1258bdd1243dSDimitry Andric SVal *ElementCountVal) { 1259bdd1243dSDimitry Andric assert(Region != nullptr && "Not-null region expected"); 1260bdd1243dSDimitry Andric 1261bdd1243dSDimitry Andric QualType Ty = ElementTy.getDesugaredType(getContext()); 1262bdd1243dSDimitry Andric while (const auto *NTy = dyn_cast<ArrayType>(Ty)) 1263bdd1243dSDimitry Andric Ty = NTy->getElementType().getDesugaredType(getContext()); 1264bdd1243dSDimitry Andric 1265bdd1243dSDimitry Andric auto ElementCount = getDynamicElementCount(State, Region, svalBuilder, Ty); 1266bdd1243dSDimitry Andric 1267bdd1243dSDimitry Andric if (ElementCountVal) 1268bdd1243dSDimitry Andric *ElementCountVal = ElementCount; 1269bdd1243dSDimitry Andric 1270bdd1243dSDimitry Andric // Note: the destructors are called in reverse order. 1271bdd1243dSDimitry Andric unsigned Idx = 0; 1272bdd1243dSDimitry Andric if (auto OptionalIdx = getPendingArrayDestruction(State, LCtx)) { 1273bdd1243dSDimitry Andric Idx = *OptionalIdx; 1274bdd1243dSDimitry Andric } else { 1275bdd1243dSDimitry Andric // The element count is either unknown, or an SVal that's not an integer. 1276bdd1243dSDimitry Andric if (!ElementCount.isConstant()) 1277bdd1243dSDimitry Andric return {State, 0}; 1278bdd1243dSDimitry Andric 1279bdd1243dSDimitry Andric Idx = ElementCount.getAsInteger()->getLimitedValue(); 1280bdd1243dSDimitry Andric } 1281bdd1243dSDimitry Andric 1282bdd1243dSDimitry Andric if (Idx == 0) 1283bdd1243dSDimitry Andric return {State, 0}; 1284bdd1243dSDimitry Andric 1285bdd1243dSDimitry Andric --Idx; 1286bdd1243dSDimitry Andric 1287bdd1243dSDimitry Andric return {setPendingArrayDestruction(State, LCtx, Idx), Idx}; 1288bdd1243dSDimitry Andric } 1289bdd1243dSDimitry Andric 12900b57cec5SDimitry Andric void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, 12910b57cec5SDimitry Andric ExplodedNode *Pred) { 12920b57cec5SDimitry Andric ExplodedNodeSet Dst; 12930b57cec5SDimitry Andric switch (D.getKind()) { 12940b57cec5SDimitry Andric case CFGElement::AutomaticObjectDtor: 12950b57cec5SDimitry Andric ProcessAutomaticObjDtor(D.castAs<CFGAutomaticObjDtor>(), Pred, Dst); 12960b57cec5SDimitry Andric break; 12970b57cec5SDimitry Andric case CFGElement::BaseDtor: 12980b57cec5SDimitry Andric ProcessBaseDtor(D.castAs<CFGBaseDtor>(), Pred, Dst); 12990b57cec5SDimitry Andric break; 13000b57cec5SDimitry Andric case CFGElement::MemberDtor: 13010b57cec5SDimitry Andric ProcessMemberDtor(D.castAs<CFGMemberDtor>(), Pred, Dst); 13020b57cec5SDimitry Andric break; 13030b57cec5SDimitry Andric case CFGElement::TemporaryDtor: 13040b57cec5SDimitry Andric ProcessTemporaryDtor(D.castAs<CFGTemporaryDtor>(), Pred, Dst); 13050b57cec5SDimitry Andric break; 13060b57cec5SDimitry Andric case CFGElement::DeleteDtor: 13070b57cec5SDimitry Andric ProcessDeleteDtor(D.castAs<CFGDeleteDtor>(), Pred, Dst); 13080b57cec5SDimitry Andric break; 13090b57cec5SDimitry Andric default: 13100b57cec5SDimitry Andric llvm_unreachable("Unexpected dtor kind."); 13110b57cec5SDimitry Andric } 13120b57cec5SDimitry Andric 13130b57cec5SDimitry Andric // Enqueue the new nodes onto the work list. 13140b57cec5SDimitry Andric Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); 13150b57cec5SDimitry Andric } 13160b57cec5SDimitry Andric 13170b57cec5SDimitry Andric void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE, 13180b57cec5SDimitry Andric ExplodedNode *Pred) { 13190b57cec5SDimitry Andric ExplodedNodeSet Dst; 13200b57cec5SDimitry Andric AnalysisManager &AMgr = getAnalysisManager(); 13210b57cec5SDimitry Andric AnalyzerOptions &Opts = AMgr.options; 13220b57cec5SDimitry Andric // TODO: We're not evaluating allocators for all cases just yet as 13230b57cec5SDimitry Andric // we're not handling the return value correctly, which causes false 13240b57cec5SDimitry Andric // positives when the alpha.cplusplus.NewDeleteLeaks check is on. 13250b57cec5SDimitry Andric if (Opts.MayInlineCXXAllocator) 13260b57cec5SDimitry Andric VisitCXXNewAllocatorCall(NE, Pred, Dst); 13270b57cec5SDimitry Andric else { 13280b57cec5SDimitry Andric NodeBuilder Bldr(Pred, Dst, *currBldrCtx); 13290b57cec5SDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 133006c3fb27SDimitry Andric PostImplicitCall PP(NE->getOperatorNew(), NE->getBeginLoc(), LCtx, 133106c3fb27SDimitry Andric getCFGElementRef()); 13320b57cec5SDimitry Andric Bldr.generateNode(PP, Pred->getState(), Pred); 13330b57cec5SDimitry Andric } 13340b57cec5SDimitry Andric Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); 13350b57cec5SDimitry Andric } 13360b57cec5SDimitry Andric 13370b57cec5SDimitry Andric void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, 13380b57cec5SDimitry Andric ExplodedNode *Pred, 13390b57cec5SDimitry Andric ExplodedNodeSet &Dst) { 1340bdd1243dSDimitry Andric const auto *DtorDecl = Dtor.getDestructorDecl(getContext()); 13410b57cec5SDimitry Andric const VarDecl *varDecl = Dtor.getVarDecl(); 13420b57cec5SDimitry Andric QualType varType = varDecl->getType(); 13430b57cec5SDimitry Andric 13440b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 1345bdd1243dSDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 1346bdd1243dSDimitry Andric 1347bdd1243dSDimitry Andric SVal dest = state->getLValue(varDecl, LCtx); 13480b57cec5SDimitry Andric const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion(); 13490b57cec5SDimitry Andric 13500b57cec5SDimitry Andric if (varType->isReferenceType()) { 13510b57cec5SDimitry Andric const MemRegion *ValueRegion = state->getSVal(Region).getAsRegion(); 13520b57cec5SDimitry Andric if (!ValueRegion) { 13530b57cec5SDimitry Andric // FIXME: This should not happen. The language guarantees a presence 13540b57cec5SDimitry Andric // of a valid initializer here, so the reference shall not be undefined. 13550b57cec5SDimitry Andric // It seems that we're calling destructors over variables that 13560b57cec5SDimitry Andric // were not initialized yet. 13570b57cec5SDimitry Andric return; 13580b57cec5SDimitry Andric } 13590b57cec5SDimitry Andric Region = ValueRegion->getBaseRegion(); 13600b57cec5SDimitry Andric varType = cast<TypedValueRegion>(Region)->getValueType(); 13610b57cec5SDimitry Andric } 13620b57cec5SDimitry Andric 1363bdd1243dSDimitry Andric unsigned Idx = 0; 1364bdd1243dSDimitry Andric if (isa<ArrayType>(varType)) { 1365bdd1243dSDimitry Andric SVal ElementCount; 1366bdd1243dSDimitry Andric std::tie(state, Idx) = prepareStateForArrayDestruction( 1367bdd1243dSDimitry Andric state, Region, varType, LCtx, &ElementCount); 1368bdd1243dSDimitry Andric 1369bdd1243dSDimitry Andric if (ElementCount.isConstant()) { 1370bdd1243dSDimitry Andric uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue(); 1371bdd1243dSDimitry Andric assert(ArrayLength && 1372bdd1243dSDimitry Andric "An automatic dtor for a 0 length array shouldn't be triggered!"); 1373bdd1243dSDimitry Andric 1374bdd1243dSDimitry Andric // Still handle this case if we don't have assertions enabled. 1375bdd1243dSDimitry Andric if (!ArrayLength) { 1376bdd1243dSDimitry Andric static SimpleProgramPointTag PT( 1377bdd1243dSDimitry Andric "ExprEngine", "Skipping automatic 0 length array destruction, " 1378bdd1243dSDimitry Andric "which shouldn't be in the CFG."); 137906c3fb27SDimitry Andric PostImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, 138006c3fb27SDimitry Andric getCFGElementRef(), &PT); 1381bdd1243dSDimitry Andric NodeBuilder Bldr(Pred, Dst, *currBldrCtx); 1382bdd1243dSDimitry Andric Bldr.generateSink(PP, Pred->getState(), Pred); 1383bdd1243dSDimitry Andric return; 1384bdd1243dSDimitry Andric } 1385bdd1243dSDimitry Andric } 1386bdd1243dSDimitry Andric } 1387bdd1243dSDimitry Andric 13880b57cec5SDimitry Andric EvalCallOptions CallOpts; 1389fcaf7f86SDimitry Andric Region = makeElementRegion(state, loc::MemRegionVal(Region), varType, 1390bdd1243dSDimitry Andric CallOpts.IsArrayCtorOrDtor, Idx) 1391fcaf7f86SDimitry Andric .getAsRegion(); 13920b57cec5SDimitry Andric 1393bdd1243dSDimitry Andric NodeBuilder Bldr(Pred, Dst, getBuilderContext()); 1394bdd1243dSDimitry Andric 1395bdd1243dSDimitry Andric static SimpleProgramPointTag PT("ExprEngine", 1396bdd1243dSDimitry Andric "Prepare for object destruction"); 139706c3fb27SDimitry Andric PreImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, getCFGElementRef(), 139806c3fb27SDimitry Andric &PT); 1399bdd1243dSDimitry Andric Pred = Bldr.generateNode(PP, state, Pred); 1400bdd1243dSDimitry Andric 1401bdd1243dSDimitry Andric if (!Pred) 1402bdd1243dSDimitry Andric return; 1403bdd1243dSDimitry Andric Bldr.takeNodes(Pred); 1404bdd1243dSDimitry Andric 1405a7dea167SDimitry Andric VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), 1406a7dea167SDimitry Andric /*IsBase=*/false, Pred, Dst, CallOpts); 14070b57cec5SDimitry Andric } 14080b57cec5SDimitry Andric 14090b57cec5SDimitry Andric void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor, 14100b57cec5SDimitry Andric ExplodedNode *Pred, 14110b57cec5SDimitry Andric ExplodedNodeSet &Dst) { 14120b57cec5SDimitry Andric ProgramStateRef State = Pred->getState(); 14130b57cec5SDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 14140b57cec5SDimitry Andric const CXXDeleteExpr *DE = Dtor.getDeleteExpr(); 14150b57cec5SDimitry Andric const Stmt *Arg = DE->getArgument(); 14160b57cec5SDimitry Andric QualType DTy = DE->getDestroyedType(); 14170b57cec5SDimitry Andric SVal ArgVal = State->getSVal(Arg, LCtx); 14180b57cec5SDimitry Andric 14190b57cec5SDimitry Andric // If the argument to delete is known to be a null value, 14200b57cec5SDimitry Andric // don't run destructor. 14210b57cec5SDimitry Andric if (State->isNull(ArgVal).isConstrainedTrue()) { 14220b57cec5SDimitry Andric QualType BTy = getContext().getBaseElementType(DTy); 14230b57cec5SDimitry Andric const CXXRecordDecl *RD = BTy->getAsCXXRecordDecl(); 14240b57cec5SDimitry Andric const CXXDestructorDecl *Dtor = RD->getDestructor(); 14250b57cec5SDimitry Andric 142606c3fb27SDimitry Andric PostImplicitCall PP(Dtor, DE->getBeginLoc(), LCtx, getCFGElementRef()); 14270b57cec5SDimitry Andric NodeBuilder Bldr(Pred, Dst, *currBldrCtx); 14280b57cec5SDimitry Andric Bldr.generateNode(PP, Pred->getState(), Pred); 14290b57cec5SDimitry Andric return; 14300b57cec5SDimitry Andric } 14310b57cec5SDimitry Andric 1432bdd1243dSDimitry Andric auto getDtorDecl = [](const QualType &DTy) { 1433bdd1243dSDimitry Andric const CXXRecordDecl *RD = DTy->getAsCXXRecordDecl(); 1434bdd1243dSDimitry Andric return RD->getDestructor(); 1435bdd1243dSDimitry Andric }; 1436bdd1243dSDimitry Andric 1437bdd1243dSDimitry Andric unsigned Idx = 0; 14380b57cec5SDimitry Andric EvalCallOptions CallOpts; 14390b57cec5SDimitry Andric const MemRegion *ArgR = ArgVal.getAsRegion(); 1440bdd1243dSDimitry Andric 14410b57cec5SDimitry Andric if (DE->isArrayForm()) { 14420b57cec5SDimitry Andric CallOpts.IsArrayCtorOrDtor = true; 14430b57cec5SDimitry Andric // Yes, it may even be a multi-dimensional array. 14440b57cec5SDimitry Andric while (const auto *AT = getContext().getAsArrayType(DTy)) 14450b57cec5SDimitry Andric DTy = AT->getElementType(); 1446bdd1243dSDimitry Andric 1447bdd1243dSDimitry Andric if (ArgR) { 1448bdd1243dSDimitry Andric SVal ElementCount; 1449bdd1243dSDimitry Andric std::tie(State, Idx) = prepareStateForArrayDestruction( 1450bdd1243dSDimitry Andric State, ArgR, DTy, LCtx, &ElementCount); 1451bdd1243dSDimitry Andric 1452bdd1243dSDimitry Andric // If we're about to destruct a 0 length array, don't run any of the 1453bdd1243dSDimitry Andric // destructors. 1454bdd1243dSDimitry Andric if (ElementCount.isConstant() && 1455bdd1243dSDimitry Andric ElementCount.getAsInteger()->getLimitedValue() == 0) { 1456bdd1243dSDimitry Andric 1457bdd1243dSDimitry Andric static SimpleProgramPointTag PT( 1458bdd1243dSDimitry Andric "ExprEngine", "Skipping 0 length array delete destruction"); 145906c3fb27SDimitry Andric PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, 146006c3fb27SDimitry Andric getCFGElementRef(), &PT); 1461bdd1243dSDimitry Andric NodeBuilder Bldr(Pred, Dst, *currBldrCtx); 1462bdd1243dSDimitry Andric Bldr.generateNode(PP, Pred->getState(), Pred); 1463bdd1243dSDimitry Andric return; 14640b57cec5SDimitry Andric } 14650b57cec5SDimitry Andric 1466bdd1243dSDimitry Andric ArgR = State->getLValue(DTy, svalBuilder.makeArrayIndex(Idx), ArgVal) 1467bdd1243dSDimitry Andric .getAsRegion(); 1468bdd1243dSDimitry Andric } 1469bdd1243dSDimitry Andric } 1470bdd1243dSDimitry Andric 1471bdd1243dSDimitry Andric NodeBuilder Bldr(Pred, Dst, getBuilderContext()); 1472bdd1243dSDimitry Andric static SimpleProgramPointTag PT("ExprEngine", 1473bdd1243dSDimitry Andric "Prepare for object destruction"); 147406c3fb27SDimitry Andric PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, 147506c3fb27SDimitry Andric getCFGElementRef(), &PT); 1476bdd1243dSDimitry Andric Pred = Bldr.generateNode(PP, State, Pred); 1477bdd1243dSDimitry Andric 1478bdd1243dSDimitry Andric if (!Pred) 1479bdd1243dSDimitry Andric return; 1480bdd1243dSDimitry Andric Bldr.takeNodes(Pred); 1481bdd1243dSDimitry Andric 14820b57cec5SDimitry Andric VisitCXXDestructor(DTy, ArgR, DE, /*IsBase=*/false, Pred, Dst, CallOpts); 14830b57cec5SDimitry Andric } 14840b57cec5SDimitry Andric 14850b57cec5SDimitry Andric void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, 14860b57cec5SDimitry Andric ExplodedNode *Pred, ExplodedNodeSet &Dst) { 14870b57cec5SDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 14880b57cec5SDimitry Andric 14890b57cec5SDimitry Andric const auto *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl()); 14900b57cec5SDimitry Andric Loc ThisPtr = getSValBuilder().getCXXThis(CurDtor, 14910b57cec5SDimitry Andric LCtx->getStackFrame()); 14920b57cec5SDimitry Andric SVal ThisVal = Pred->getState()->getSVal(ThisPtr); 14930b57cec5SDimitry Andric 14940b57cec5SDimitry Andric // Create the base object region. 14950b57cec5SDimitry Andric const CXXBaseSpecifier *Base = D.getBaseSpecifier(); 14960b57cec5SDimitry Andric QualType BaseTy = Base->getType(); 14970b57cec5SDimitry Andric SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy, 14980b57cec5SDimitry Andric Base->isVirtual()); 14990b57cec5SDimitry Andric 1500a7dea167SDimitry Andric EvalCallOptions CallOpts; 1501a7dea167SDimitry Andric VisitCXXDestructor(BaseTy, BaseVal.getAsRegion(), CurDtor->getBody(), 1502a7dea167SDimitry Andric /*IsBase=*/true, Pred, Dst, CallOpts); 15030b57cec5SDimitry Andric } 15040b57cec5SDimitry Andric 15050b57cec5SDimitry Andric void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, 15060b57cec5SDimitry Andric ExplodedNode *Pred, ExplodedNodeSet &Dst) { 1507bdd1243dSDimitry Andric const auto *DtorDecl = D.getDestructorDecl(getContext()); 15080b57cec5SDimitry Andric const FieldDecl *Member = D.getFieldDecl(); 15090b57cec5SDimitry Andric QualType T = Member->getType(); 15100b57cec5SDimitry Andric ProgramStateRef State = Pred->getState(); 15110b57cec5SDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 15120b57cec5SDimitry Andric 15130b57cec5SDimitry Andric const auto *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl()); 1514a7dea167SDimitry Andric Loc ThisStorageLoc = 1515a7dea167SDimitry Andric getSValBuilder().getCXXThis(CurDtor, LCtx->getStackFrame()); 1516a7dea167SDimitry Andric Loc ThisLoc = State->getSVal(ThisStorageLoc).castAs<Loc>(); 1517a7dea167SDimitry Andric SVal FieldVal = State->getLValue(Member, ThisLoc); 15180b57cec5SDimitry Andric 1519bdd1243dSDimitry Andric unsigned Idx = 0; 1520bdd1243dSDimitry Andric if (isa<ArrayType>(T)) { 1521bdd1243dSDimitry Andric SVal ElementCount; 1522bdd1243dSDimitry Andric std::tie(State, Idx) = prepareStateForArrayDestruction( 1523bdd1243dSDimitry Andric State, FieldVal.getAsRegion(), T, LCtx, &ElementCount); 1524bdd1243dSDimitry Andric 1525bdd1243dSDimitry Andric if (ElementCount.isConstant()) { 1526bdd1243dSDimitry Andric uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue(); 1527bdd1243dSDimitry Andric assert(ArrayLength && 1528bdd1243dSDimitry Andric "A member dtor for a 0 length array shouldn't be triggered!"); 1529bdd1243dSDimitry Andric 1530bdd1243dSDimitry Andric // Still handle this case if we don't have assertions enabled. 1531bdd1243dSDimitry Andric if (!ArrayLength) { 1532bdd1243dSDimitry Andric static SimpleProgramPointTag PT( 1533bdd1243dSDimitry Andric "ExprEngine", "Skipping member 0 length array destruction, which " 1534bdd1243dSDimitry Andric "shouldn't be in the CFG."); 153506c3fb27SDimitry Andric PostImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, 153606c3fb27SDimitry Andric getCFGElementRef(), &PT); 1537bdd1243dSDimitry Andric NodeBuilder Bldr(Pred, Dst, *currBldrCtx); 1538bdd1243dSDimitry Andric Bldr.generateSink(PP, Pred->getState(), Pred); 1539bdd1243dSDimitry Andric return; 1540bdd1243dSDimitry Andric } 1541bdd1243dSDimitry Andric } 1542bdd1243dSDimitry Andric } 1543bdd1243dSDimitry Andric 15440b57cec5SDimitry Andric EvalCallOptions CallOpts; 1545bdd1243dSDimitry Andric FieldVal = 1546bdd1243dSDimitry Andric makeElementRegion(State, FieldVal, T, CallOpts.IsArrayCtorOrDtor, Idx); 1547bdd1243dSDimitry Andric 1548bdd1243dSDimitry Andric NodeBuilder Bldr(Pred, Dst, getBuilderContext()); 1549bdd1243dSDimitry Andric 1550bdd1243dSDimitry Andric static SimpleProgramPointTag PT("ExprEngine", 1551bdd1243dSDimitry Andric "Prepare for object destruction"); 155206c3fb27SDimitry Andric PreImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, getCFGElementRef(), 155306c3fb27SDimitry Andric &PT); 1554bdd1243dSDimitry Andric Pred = Bldr.generateNode(PP, State, Pred); 1555bdd1243dSDimitry Andric 1556bdd1243dSDimitry Andric if (!Pred) 1557bdd1243dSDimitry Andric return; 1558bdd1243dSDimitry Andric Bldr.takeNodes(Pred); 15590b57cec5SDimitry Andric 1560a7dea167SDimitry Andric VisitCXXDestructor(T, FieldVal.getAsRegion(), CurDtor->getBody(), 1561a7dea167SDimitry Andric /*IsBase=*/false, Pred, Dst, CallOpts); 15620b57cec5SDimitry Andric } 15630b57cec5SDimitry Andric 15640b57cec5SDimitry Andric void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, 15650b57cec5SDimitry Andric ExplodedNode *Pred, 15660b57cec5SDimitry Andric ExplodedNodeSet &Dst) { 15670b57cec5SDimitry Andric const CXXBindTemporaryExpr *BTE = D.getBindTemporaryExpr(); 15680b57cec5SDimitry Andric ProgramStateRef State = Pred->getState(); 15690b57cec5SDimitry Andric const LocationContext *LC = Pred->getLocationContext(); 15700b57cec5SDimitry Andric const MemRegion *MR = nullptr; 15710b57cec5SDimitry Andric 1572bdd1243dSDimitry Andric if (std::optional<SVal> V = getObjectUnderConstruction( 1573bdd1243dSDimitry Andric State, D.getBindTemporaryExpr(), Pred->getLocationContext())) { 15740b57cec5SDimitry Andric // FIXME: Currently we insert temporary destructors for default parameters, 15750b57cec5SDimitry Andric // but we don't insert the constructors, so the entry in 15760b57cec5SDimitry Andric // ObjectsUnderConstruction may be missing. 15770b57cec5SDimitry Andric State = finishObjectConstruction(State, D.getBindTemporaryExpr(), 15780b57cec5SDimitry Andric Pred->getLocationContext()); 15790b57cec5SDimitry Andric MR = V->getAsRegion(); 15800b57cec5SDimitry Andric } 15810b57cec5SDimitry Andric 15820b57cec5SDimitry Andric // If copy elision has occurred, and the constructor corresponding to the 15830b57cec5SDimitry Andric // destructor was elided, we need to skip the destructor as well. 15840b57cec5SDimitry Andric if (isDestructorElided(State, BTE, LC)) { 15850b57cec5SDimitry Andric State = cleanupElidedDestructor(State, BTE, LC); 15860b57cec5SDimitry Andric NodeBuilder Bldr(Pred, Dst, *currBldrCtx); 15870b57cec5SDimitry Andric PostImplicitCall PP(D.getDestructorDecl(getContext()), 15880b57cec5SDimitry Andric D.getBindTemporaryExpr()->getBeginLoc(), 158906c3fb27SDimitry Andric Pred->getLocationContext(), getCFGElementRef()); 15900b57cec5SDimitry Andric Bldr.generateNode(PP, State, Pred); 15910b57cec5SDimitry Andric return; 15920b57cec5SDimitry Andric } 15930b57cec5SDimitry Andric 15940b57cec5SDimitry Andric ExplodedNodeSet CleanDtorState; 15950b57cec5SDimitry Andric StmtNodeBuilder StmtBldr(Pred, CleanDtorState, *currBldrCtx); 15960b57cec5SDimitry Andric StmtBldr.generateNode(D.getBindTemporaryExpr(), Pred, State); 15970b57cec5SDimitry Andric 15980b57cec5SDimitry Andric QualType T = D.getBindTemporaryExpr()->getSubExpr()->getType(); 15990b57cec5SDimitry Andric // FIXME: Currently CleanDtorState can be empty here due to temporaries being 16000b57cec5SDimitry Andric // bound to default parameters. 16010b57cec5SDimitry Andric assert(CleanDtorState.size() <= 1); 16020b57cec5SDimitry Andric ExplodedNode *CleanPred = 16030b57cec5SDimitry Andric CleanDtorState.empty() ? Pred : *CleanDtorState.begin(); 16040b57cec5SDimitry Andric 16050b57cec5SDimitry Andric EvalCallOptions CallOpts; 16060b57cec5SDimitry Andric CallOpts.IsTemporaryCtorOrDtor = true; 16070b57cec5SDimitry Andric if (!MR) { 1608bdd1243dSDimitry Andric // FIXME: If we have no MR, we still need to unwrap the array to avoid 1609bdd1243dSDimitry Andric // destroying the whole array at once. 1610bdd1243dSDimitry Andric // 1611bdd1243dSDimitry Andric // For this case there is no universal solution as there is no way to 1612bdd1243dSDimitry Andric // directly create an array of temporary objects. There are some expressions 1613bdd1243dSDimitry Andric // however which can create temporary objects and have an array type. 1614bdd1243dSDimitry Andric // 1615bdd1243dSDimitry Andric // E.g.: std::initializer_list<S>{S(), S()}; 1616bdd1243dSDimitry Andric // 1617bdd1243dSDimitry Andric // The expression above has a type of 'const struct S[2]' but it's a single 1618bdd1243dSDimitry Andric // 'std::initializer_list<>'. The destructors of the 2 temporary 'S()' 1619bdd1243dSDimitry Andric // objects will be called anyway, because they are 2 separate objects in 2 1620bdd1243dSDimitry Andric // separate clusters, i.e.: not an array. 1621bdd1243dSDimitry Andric // 1622bdd1243dSDimitry Andric // Now the 'std::initializer_list<>' is not an array either even though it 1623bdd1243dSDimitry Andric // has the type of an array. The point is, we only want to invoke the 1624bdd1243dSDimitry Andric // destructor for the initializer list once not twice or so. 16250b57cec5SDimitry Andric while (const ArrayType *AT = getContext().getAsArrayType(T)) { 16260b57cec5SDimitry Andric T = AT->getElementType(); 1627bdd1243dSDimitry Andric 1628bdd1243dSDimitry Andric // FIXME: Enable this flag once we handle this case properly. 1629bdd1243dSDimitry Andric // CallOpts.IsArrayCtorOrDtor = true; 16300b57cec5SDimitry Andric } 16310b57cec5SDimitry Andric } else { 1632bdd1243dSDimitry Andric // FIXME: We'd eventually need to makeElementRegion() trick here, 16330b57cec5SDimitry Andric // but for now we don't have the respective construction contexts, 16340b57cec5SDimitry Andric // so MR would always be null in this case. Do nothing for now. 16350b57cec5SDimitry Andric } 16360b57cec5SDimitry Andric VisitCXXDestructor(T, MR, D.getBindTemporaryExpr(), 16370b57cec5SDimitry Andric /*IsBase=*/false, CleanPred, Dst, CallOpts); 16380b57cec5SDimitry Andric } 16390b57cec5SDimitry Andric 16400b57cec5SDimitry Andric void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, 16410b57cec5SDimitry Andric NodeBuilderContext &BldCtx, 16420b57cec5SDimitry Andric ExplodedNode *Pred, 16430b57cec5SDimitry Andric ExplodedNodeSet &Dst, 16440b57cec5SDimitry Andric const CFGBlock *DstT, 16450b57cec5SDimitry Andric const CFGBlock *DstF) { 16460b57cec5SDimitry Andric BranchNodeBuilder TempDtorBuilder(Pred, Dst, BldCtx, DstT, DstF); 16470b57cec5SDimitry Andric ProgramStateRef State = Pred->getState(); 16480b57cec5SDimitry Andric const LocationContext *LC = Pred->getLocationContext(); 16490b57cec5SDimitry Andric if (getObjectUnderConstruction(State, BTE, LC)) { 16500b57cec5SDimitry Andric TempDtorBuilder.markInfeasible(false); 16510b57cec5SDimitry Andric TempDtorBuilder.generateNode(State, true, Pred); 16520b57cec5SDimitry Andric } else { 16530b57cec5SDimitry Andric TempDtorBuilder.markInfeasible(true); 16540b57cec5SDimitry Andric TempDtorBuilder.generateNode(State, false, Pred); 16550b57cec5SDimitry Andric } 16560b57cec5SDimitry Andric } 16570b57cec5SDimitry Andric 16580b57cec5SDimitry Andric void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, 16590b57cec5SDimitry Andric ExplodedNodeSet &PreVisit, 16600b57cec5SDimitry Andric ExplodedNodeSet &Dst) { 16610b57cec5SDimitry Andric // This is a fallback solution in case we didn't have a construction 16620b57cec5SDimitry Andric // context when we were constructing the temporary. Otherwise the map should 16630b57cec5SDimitry Andric // have been populated there. 16640b57cec5SDimitry Andric if (!getAnalysisManager().options.ShouldIncludeTemporaryDtorsInCFG) { 16650b57cec5SDimitry Andric // In case we don't have temporary destructors in the CFG, do not mark 16660b57cec5SDimitry Andric // the initialization - we would otherwise never clean it up. 16670b57cec5SDimitry Andric Dst = PreVisit; 16680b57cec5SDimitry Andric return; 16690b57cec5SDimitry Andric } 16700b57cec5SDimitry Andric StmtNodeBuilder StmtBldr(PreVisit, Dst, *currBldrCtx); 16710b57cec5SDimitry Andric for (ExplodedNode *Node : PreVisit) { 16720b57cec5SDimitry Andric ProgramStateRef State = Node->getState(); 16730b57cec5SDimitry Andric const LocationContext *LC = Node->getLocationContext(); 16740b57cec5SDimitry Andric if (!getObjectUnderConstruction(State, BTE, LC)) { 16750b57cec5SDimitry Andric // FIXME: Currently the state might also already contain the marker due to 16760b57cec5SDimitry Andric // incorrect handling of temporaries bound to default parameters; for 16770b57cec5SDimitry Andric // those, we currently skip the CXXBindTemporaryExpr but rely on adding 16780b57cec5SDimitry Andric // temporary destructor nodes. 16790b57cec5SDimitry Andric State = addObjectUnderConstruction(State, BTE, LC, UnknownVal()); 16800b57cec5SDimitry Andric } 16810b57cec5SDimitry Andric StmtBldr.generateNode(BTE, Node, State); 16820b57cec5SDimitry Andric } 16830b57cec5SDimitry Andric } 16840b57cec5SDimitry Andric 1685480093f4SDimitry Andric ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State, 1686480093f4SDimitry Andric ArrayRef<SVal> Vs, 1687480093f4SDimitry Andric PointerEscapeKind K, 1688480093f4SDimitry Andric const CallEvent *Call) const { 16890b57cec5SDimitry Andric class CollectReachableSymbolsCallback final : public SymbolVisitor { 1690480093f4SDimitry Andric InvalidatedSymbols &Symbols; 16910b57cec5SDimitry Andric 16920b57cec5SDimitry Andric public: 1693480093f4SDimitry Andric explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols) 1694480093f4SDimitry Andric : Symbols(Symbols) {} 16950b57cec5SDimitry Andric 16960b57cec5SDimitry Andric const InvalidatedSymbols &getSymbols() const { return Symbols; } 16970b57cec5SDimitry Andric 16980b57cec5SDimitry Andric bool VisitSymbol(SymbolRef Sym) override { 16990b57cec5SDimitry Andric Symbols.insert(Sym); 17000b57cec5SDimitry Andric return true; 17010b57cec5SDimitry Andric } 17020b57cec5SDimitry Andric }; 1703480093f4SDimitry Andric InvalidatedSymbols Symbols; 1704480093f4SDimitry Andric CollectReachableSymbolsCallback CallBack(Symbols); 1705480093f4SDimitry Andric for (SVal V : Vs) 1706480093f4SDimitry Andric State->scanReachableSymbols(V, CallBack); 17070b57cec5SDimitry Andric 17080b57cec5SDimitry Andric return getCheckerManager().runCheckersForPointerEscape( 1709480093f4SDimitry Andric State, CallBack.getSymbols(), Call, K, nullptr); 17100b57cec5SDimitry Andric } 17110b57cec5SDimitry Andric 17120b57cec5SDimitry Andric void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, 17130b57cec5SDimitry Andric ExplodedNodeSet &DstTop) { 17140b57cec5SDimitry Andric PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), 17150b57cec5SDimitry Andric S->getBeginLoc(), "Error evaluating statement"); 17160b57cec5SDimitry Andric ExplodedNodeSet Dst; 17170b57cec5SDimitry Andric StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx); 17180b57cec5SDimitry Andric 17190b57cec5SDimitry Andric assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens()); 17200b57cec5SDimitry Andric 17210b57cec5SDimitry Andric switch (S->getStmtClass()) { 17220b57cec5SDimitry Andric // C++, OpenMP and ARC stuff we don't support yet. 17230b57cec5SDimitry Andric case Stmt::CXXDependentScopeMemberExprClass: 17240b57cec5SDimitry Andric case Stmt::CXXTryStmtClass: 17250b57cec5SDimitry Andric case Stmt::CXXTypeidExprClass: 17260b57cec5SDimitry Andric case Stmt::CXXUuidofExprClass: 17270b57cec5SDimitry Andric case Stmt::CXXFoldExprClass: 17280b57cec5SDimitry Andric case Stmt::MSPropertyRefExprClass: 17290b57cec5SDimitry Andric case Stmt::MSPropertySubscriptExprClass: 17300b57cec5SDimitry Andric case Stmt::CXXUnresolvedConstructExprClass: 17310b57cec5SDimitry Andric case Stmt::DependentScopeDeclRefExprClass: 17320b57cec5SDimitry Andric case Stmt::ArrayTypeTraitExprClass: 17330b57cec5SDimitry Andric case Stmt::ExpressionTraitExprClass: 17340b57cec5SDimitry Andric case Stmt::UnresolvedLookupExprClass: 17350b57cec5SDimitry Andric case Stmt::UnresolvedMemberExprClass: 17360b57cec5SDimitry Andric case Stmt::TypoExprClass: 17375ffd83dbSDimitry Andric case Stmt::RecoveryExprClass: 17380b57cec5SDimitry Andric case Stmt::CXXNoexceptExprClass: 17390b57cec5SDimitry Andric case Stmt::PackExpansionExprClass: 17400fca6ea1SDimitry Andric case Stmt::PackIndexingExprClass: 17410b57cec5SDimitry Andric case Stmt::SubstNonTypeTemplateParmPackExprClass: 17420b57cec5SDimitry Andric case Stmt::FunctionParmPackExprClass: 17430b57cec5SDimitry Andric case Stmt::CoroutineBodyStmtClass: 17440b57cec5SDimitry Andric case Stmt::CoawaitExprClass: 17450b57cec5SDimitry Andric case Stmt::DependentCoawaitExprClass: 17460b57cec5SDimitry Andric case Stmt::CoreturnStmtClass: 17470b57cec5SDimitry Andric case Stmt::CoyieldExprClass: 17480b57cec5SDimitry Andric case Stmt::SEHTryStmtClass: 17490b57cec5SDimitry Andric case Stmt::SEHExceptStmtClass: 17500b57cec5SDimitry Andric case Stmt::SEHLeaveStmtClass: 17510b57cec5SDimitry Andric case Stmt::SEHFinallyStmtClass: 1752fe6060f1SDimitry Andric case Stmt::OMPCanonicalLoopClass: 17530b57cec5SDimitry Andric case Stmt::OMPParallelDirectiveClass: 17540b57cec5SDimitry Andric case Stmt::OMPSimdDirectiveClass: 17550b57cec5SDimitry Andric case Stmt::OMPForDirectiveClass: 17560b57cec5SDimitry Andric case Stmt::OMPForSimdDirectiveClass: 17570b57cec5SDimitry Andric case Stmt::OMPSectionsDirectiveClass: 17580b57cec5SDimitry Andric case Stmt::OMPSectionDirectiveClass: 17595f757f3fSDimitry Andric case Stmt::OMPScopeDirectiveClass: 17600b57cec5SDimitry Andric case Stmt::OMPSingleDirectiveClass: 17610b57cec5SDimitry Andric case Stmt::OMPMasterDirectiveClass: 17620b57cec5SDimitry Andric case Stmt::OMPCriticalDirectiveClass: 17630b57cec5SDimitry Andric case Stmt::OMPParallelForDirectiveClass: 17640b57cec5SDimitry Andric case Stmt::OMPParallelForSimdDirectiveClass: 17650b57cec5SDimitry Andric case Stmt::OMPParallelSectionsDirectiveClass: 1766480093f4SDimitry Andric case Stmt::OMPParallelMasterDirectiveClass: 176781ad6265SDimitry Andric case Stmt::OMPParallelMaskedDirectiveClass: 17680b57cec5SDimitry Andric case Stmt::OMPTaskDirectiveClass: 17690b57cec5SDimitry Andric case Stmt::OMPTaskyieldDirectiveClass: 17700b57cec5SDimitry Andric case Stmt::OMPBarrierDirectiveClass: 17710b57cec5SDimitry Andric case Stmt::OMPTaskwaitDirectiveClass: 1772bdd1243dSDimitry Andric case Stmt::OMPErrorDirectiveClass: 17730b57cec5SDimitry Andric case Stmt::OMPTaskgroupDirectiveClass: 17740b57cec5SDimitry Andric case Stmt::OMPFlushDirectiveClass: 17755ffd83dbSDimitry Andric case Stmt::OMPDepobjDirectiveClass: 17765ffd83dbSDimitry Andric case Stmt::OMPScanDirectiveClass: 17770b57cec5SDimitry Andric case Stmt::OMPOrderedDirectiveClass: 17780b57cec5SDimitry Andric case Stmt::OMPAtomicDirectiveClass: 17790b57cec5SDimitry Andric case Stmt::OMPTargetDirectiveClass: 17800b57cec5SDimitry Andric case Stmt::OMPTargetDataDirectiveClass: 17810b57cec5SDimitry Andric case Stmt::OMPTargetEnterDataDirectiveClass: 17820b57cec5SDimitry Andric case Stmt::OMPTargetExitDataDirectiveClass: 17830b57cec5SDimitry Andric case Stmt::OMPTargetParallelDirectiveClass: 17840b57cec5SDimitry Andric case Stmt::OMPTargetParallelForDirectiveClass: 17850b57cec5SDimitry Andric case Stmt::OMPTargetUpdateDirectiveClass: 17860b57cec5SDimitry Andric case Stmt::OMPTeamsDirectiveClass: 17870b57cec5SDimitry Andric case Stmt::OMPCancellationPointDirectiveClass: 17880b57cec5SDimitry Andric case Stmt::OMPCancelDirectiveClass: 17890b57cec5SDimitry Andric case Stmt::OMPTaskLoopDirectiveClass: 17900b57cec5SDimitry Andric case Stmt::OMPTaskLoopSimdDirectiveClass: 1791a7dea167SDimitry Andric case Stmt::OMPMasterTaskLoopDirectiveClass: 179281ad6265SDimitry Andric case Stmt::OMPMaskedTaskLoopDirectiveClass: 1793a7dea167SDimitry Andric case Stmt::OMPMasterTaskLoopSimdDirectiveClass: 179481ad6265SDimitry Andric case Stmt::OMPMaskedTaskLoopSimdDirectiveClass: 1795a7dea167SDimitry Andric case Stmt::OMPParallelMasterTaskLoopDirectiveClass: 179681ad6265SDimitry Andric case Stmt::OMPParallelMaskedTaskLoopDirectiveClass: 1797480093f4SDimitry Andric case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass: 179881ad6265SDimitry Andric case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass: 17990b57cec5SDimitry Andric case Stmt::OMPDistributeDirectiveClass: 18000b57cec5SDimitry Andric case Stmt::OMPDistributeParallelForDirectiveClass: 18010b57cec5SDimitry Andric case Stmt::OMPDistributeParallelForSimdDirectiveClass: 18020b57cec5SDimitry Andric case Stmt::OMPDistributeSimdDirectiveClass: 18030b57cec5SDimitry Andric case Stmt::OMPTargetParallelForSimdDirectiveClass: 18040b57cec5SDimitry Andric case Stmt::OMPTargetSimdDirectiveClass: 18050b57cec5SDimitry Andric case Stmt::OMPTeamsDistributeDirectiveClass: 18060b57cec5SDimitry Andric case Stmt::OMPTeamsDistributeSimdDirectiveClass: 18070b57cec5SDimitry Andric case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: 18080b57cec5SDimitry Andric case Stmt::OMPTeamsDistributeParallelForDirectiveClass: 18090b57cec5SDimitry Andric case Stmt::OMPTargetTeamsDirectiveClass: 18100b57cec5SDimitry Andric case Stmt::OMPTargetTeamsDistributeDirectiveClass: 18110b57cec5SDimitry Andric case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: 18120b57cec5SDimitry Andric case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: 18130b57cec5SDimitry Andric case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: 18140fca6ea1SDimitry Andric case Stmt::OMPReverseDirectiveClass: 1815fe6060f1SDimitry Andric case Stmt::OMPTileDirectiveClass: 18160fca6ea1SDimitry Andric case Stmt::OMPInterchangeDirectiveClass: 1817fe6060f1SDimitry Andric case Stmt::OMPInteropDirectiveClass: 1818fe6060f1SDimitry Andric case Stmt::OMPDispatchDirectiveClass: 1819fe6060f1SDimitry Andric case Stmt::OMPMaskedDirectiveClass: 1820349cc55cSDimitry Andric case Stmt::OMPGenericLoopDirectiveClass: 182181ad6265SDimitry Andric case Stmt::OMPTeamsGenericLoopDirectiveClass: 182281ad6265SDimitry Andric case Stmt::OMPTargetTeamsGenericLoopDirectiveClass: 182381ad6265SDimitry Andric case Stmt::OMPParallelGenericLoopDirectiveClass: 182481ad6265SDimitry Andric case Stmt::OMPTargetParallelGenericLoopDirectiveClass: 1825fe6060f1SDimitry Andric case Stmt::CapturedStmtClass: 18260fca6ea1SDimitry Andric case Stmt::OpenACCComputeConstructClass: 18270fca6ea1SDimitry Andric case Stmt::OpenACCLoopConstructClass: 1828349cc55cSDimitry Andric case Stmt::OMPUnrollDirectiveClass: 1829349cc55cSDimitry Andric case Stmt::OMPMetaDirectiveClass: { 18300b57cec5SDimitry Andric const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); 18310b57cec5SDimitry Andric Engine.addAbortedBlock(node, currBldrCtx->getBlock()); 18320b57cec5SDimitry Andric break; 18330b57cec5SDimitry Andric } 18340b57cec5SDimitry Andric 18350b57cec5SDimitry Andric case Stmt::ParenExprClass: 18360b57cec5SDimitry Andric llvm_unreachable("ParenExprs already handled."); 18370b57cec5SDimitry Andric case Stmt::GenericSelectionExprClass: 18380b57cec5SDimitry Andric llvm_unreachable("GenericSelectionExprs already handled."); 18390b57cec5SDimitry Andric // Cases that should never be evaluated simply because they shouldn't 18400b57cec5SDimitry Andric // appear in the CFG. 18410b57cec5SDimitry Andric case Stmt::BreakStmtClass: 18420b57cec5SDimitry Andric case Stmt::CaseStmtClass: 18430b57cec5SDimitry Andric case Stmt::CompoundStmtClass: 18440b57cec5SDimitry Andric case Stmt::ContinueStmtClass: 18450b57cec5SDimitry Andric case Stmt::CXXForRangeStmtClass: 18460b57cec5SDimitry Andric case Stmt::DefaultStmtClass: 18470b57cec5SDimitry Andric case Stmt::DoStmtClass: 18480b57cec5SDimitry Andric case Stmt::ForStmtClass: 18490b57cec5SDimitry Andric case Stmt::GotoStmtClass: 18500b57cec5SDimitry Andric case Stmt::IfStmtClass: 18510b57cec5SDimitry Andric case Stmt::IndirectGotoStmtClass: 18520b57cec5SDimitry Andric case Stmt::LabelStmtClass: 18530b57cec5SDimitry Andric case Stmt::NoStmtClass: 18540b57cec5SDimitry Andric case Stmt::NullStmtClass: 18550b57cec5SDimitry Andric case Stmt::SwitchStmtClass: 18560b57cec5SDimitry Andric case Stmt::WhileStmtClass: 18570b57cec5SDimitry Andric case Expr::MSDependentExistsStmtClass: 18580b57cec5SDimitry Andric llvm_unreachable("Stmt should not be in analyzer evaluation loop"); 1859480093f4SDimitry Andric case Stmt::ImplicitValueInitExprClass: 1860480093f4SDimitry Andric // These nodes are shared in the CFG and would case caching out. 1861480093f4SDimitry Andric // Moreover, no additional evaluation required for them, the 1862480093f4SDimitry Andric // analyzer can reconstruct these values from the AST. 1863480093f4SDimitry Andric llvm_unreachable("Should be pruned from CFG"); 18640b57cec5SDimitry Andric 18650b57cec5SDimitry Andric case Stmt::ObjCSubscriptRefExprClass: 18660b57cec5SDimitry Andric case Stmt::ObjCPropertyRefExprClass: 18670b57cec5SDimitry Andric llvm_unreachable("These are handled by PseudoObjectExpr"); 18680b57cec5SDimitry Andric 18690b57cec5SDimitry Andric case Stmt::GNUNullExprClass: { 18700b57cec5SDimitry Andric // GNU __null is a pointer-width integer, not an actual pointer. 18710b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 187281ad6265SDimitry Andric state = state->BindExpr( 187381ad6265SDimitry Andric S, Pred->getLocationContext(), 187481ad6265SDimitry Andric svalBuilder.makeIntValWithWidth(getContext().VoidPtrTy, 0)); 18750b57cec5SDimitry Andric Bldr.generateNode(S, Pred, state); 18760b57cec5SDimitry Andric break; 18770b57cec5SDimitry Andric } 18780b57cec5SDimitry Andric 18790b57cec5SDimitry Andric case Stmt::ObjCAtSynchronizedStmtClass: 18800b57cec5SDimitry Andric Bldr.takeNodes(Pred); 18810b57cec5SDimitry Andric VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst); 18820b57cec5SDimitry Andric Bldr.addNodes(Dst); 18830b57cec5SDimitry Andric break; 18840b57cec5SDimitry Andric 18850b57cec5SDimitry Andric case Expr::ConstantExprClass: 18860b57cec5SDimitry Andric case Stmt::ExprWithCleanupsClass: 18870b57cec5SDimitry Andric // Handled due to fully linearised CFG. 18880b57cec5SDimitry Andric break; 18890b57cec5SDimitry Andric 18900b57cec5SDimitry Andric case Stmt::CXXBindTemporaryExprClass: { 18910b57cec5SDimitry Andric Bldr.takeNodes(Pred); 18920b57cec5SDimitry Andric ExplodedNodeSet PreVisit; 18930b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); 18940b57cec5SDimitry Andric ExplodedNodeSet Next; 18950b57cec5SDimitry Andric VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), PreVisit, Next); 18960b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, Next, S, *this); 18970b57cec5SDimitry Andric Bldr.addNodes(Dst); 18980b57cec5SDimitry Andric break; 18990b57cec5SDimitry Andric } 19000b57cec5SDimitry Andric 190181ad6265SDimitry Andric case Stmt::ArrayInitLoopExprClass: 190281ad6265SDimitry Andric Bldr.takeNodes(Pred); 190381ad6265SDimitry Andric VisitArrayInitLoopExpr(cast<ArrayInitLoopExpr>(S), Pred, Dst); 190481ad6265SDimitry Andric Bldr.addNodes(Dst); 190581ad6265SDimitry Andric break; 19060b57cec5SDimitry Andric // Cases not handled yet; but will handle some day. 19070b57cec5SDimitry Andric case Stmt::DesignatedInitExprClass: 19080b57cec5SDimitry Andric case Stmt::DesignatedInitUpdateExprClass: 19090b57cec5SDimitry Andric case Stmt::ArrayInitIndexExprClass: 19100b57cec5SDimitry Andric case Stmt::ExtVectorElementExprClass: 19110b57cec5SDimitry Andric case Stmt::ImaginaryLiteralClass: 19120b57cec5SDimitry Andric case Stmt::ObjCAtCatchStmtClass: 19130b57cec5SDimitry Andric case Stmt::ObjCAtFinallyStmtClass: 19140b57cec5SDimitry Andric case Stmt::ObjCAtTryStmtClass: 19150b57cec5SDimitry Andric case Stmt::ObjCAutoreleasePoolStmtClass: 19160b57cec5SDimitry Andric case Stmt::ObjCEncodeExprClass: 19170b57cec5SDimitry Andric case Stmt::ObjCIsaExprClass: 19180b57cec5SDimitry Andric case Stmt::ObjCProtocolExprClass: 19190b57cec5SDimitry Andric case Stmt::ObjCSelectorExprClass: 19200b57cec5SDimitry Andric case Stmt::ParenListExprClass: 19210b57cec5SDimitry Andric case Stmt::ShuffleVectorExprClass: 19220b57cec5SDimitry Andric case Stmt::ConvertVectorExprClass: 19230b57cec5SDimitry Andric case Stmt::VAArgExprClass: 19240b57cec5SDimitry Andric case Stmt::CUDAKernelCallExprClass: 19250b57cec5SDimitry Andric case Stmt::OpaqueValueExprClass: 19260b57cec5SDimitry Andric case Stmt::AsTypeExprClass: 1927a7dea167SDimitry Andric case Stmt::ConceptSpecializationExprClass: 1928a7dea167SDimitry Andric case Stmt::CXXRewrittenBinaryOperatorClass: 192955e4f9d5SDimitry Andric case Stmt::RequiresExprClass: 1930bdd1243dSDimitry Andric case Expr::CXXParenListInitExprClass: 1931*c80e69b0SDimitry Andric case Stmt::EmbedExprClass: 19320b57cec5SDimitry Andric // Fall through. 19330b57cec5SDimitry Andric 19340b57cec5SDimitry Andric // Cases we intentionally don't evaluate, since they don't need 19350b57cec5SDimitry Andric // to be explicitly evaluated. 19360b57cec5SDimitry Andric case Stmt::PredefinedExprClass: 19370b57cec5SDimitry Andric case Stmt::AddrLabelExprClass: 19380b57cec5SDimitry Andric case Stmt::AttributedStmtClass: 19390b57cec5SDimitry Andric case Stmt::IntegerLiteralClass: 19400b57cec5SDimitry Andric case Stmt::FixedPointLiteralClass: 19410b57cec5SDimitry Andric case Stmt::CharacterLiteralClass: 19420b57cec5SDimitry Andric case Stmt::CXXScalarValueInitExprClass: 19430b57cec5SDimitry Andric case Stmt::CXXBoolLiteralExprClass: 19440b57cec5SDimitry Andric case Stmt::ObjCBoolLiteralExprClass: 19450b57cec5SDimitry Andric case Stmt::ObjCAvailabilityCheckExprClass: 19460b57cec5SDimitry Andric case Stmt::FloatingLiteralClass: 19470b57cec5SDimitry Andric case Stmt::NoInitExprClass: 19480b57cec5SDimitry Andric case Stmt::SizeOfPackExprClass: 19490b57cec5SDimitry Andric case Stmt::StringLiteralClass: 19500b57cec5SDimitry Andric case Stmt::SourceLocExprClass: 19510b57cec5SDimitry Andric case Stmt::ObjCStringLiteralClass: 19520b57cec5SDimitry Andric case Stmt::CXXPseudoDestructorExprClass: 19530b57cec5SDimitry Andric case Stmt::SubstNonTypeTemplateParmExprClass: 19540b57cec5SDimitry Andric case Stmt::CXXNullPtrLiteralExprClass: 19550fca6ea1SDimitry Andric case Stmt::ArraySectionExprClass: 19565ffd83dbSDimitry Andric case Stmt::OMPArrayShapingExprClass: 19575ffd83dbSDimitry Andric case Stmt::OMPIteratorExprClass: 1958fe6060f1SDimitry Andric case Stmt::SYCLUniqueStableNameExprClass: 19590b57cec5SDimitry Andric case Stmt::TypeTraitExprClass: { 19600b57cec5SDimitry Andric Bldr.takeNodes(Pred); 19610b57cec5SDimitry Andric ExplodedNodeSet preVisit; 19620b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this); 19630b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, preVisit, S, *this); 19640b57cec5SDimitry Andric Bldr.addNodes(Dst); 19650b57cec5SDimitry Andric break; 19660b57cec5SDimitry Andric } 19670b57cec5SDimitry Andric 19680b57cec5SDimitry Andric case Stmt::CXXDefaultArgExprClass: 19690b57cec5SDimitry Andric case Stmt::CXXDefaultInitExprClass: { 19700b57cec5SDimitry Andric Bldr.takeNodes(Pred); 19710b57cec5SDimitry Andric ExplodedNodeSet PreVisit; 19720b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); 19730b57cec5SDimitry Andric 19740b57cec5SDimitry Andric ExplodedNodeSet Tmp; 19750b57cec5SDimitry Andric StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx); 19760b57cec5SDimitry Andric 19770b57cec5SDimitry Andric const Expr *ArgE; 19780b57cec5SDimitry Andric if (const auto *DefE = dyn_cast<CXXDefaultArgExpr>(S)) 19790b57cec5SDimitry Andric ArgE = DefE->getExpr(); 19800b57cec5SDimitry Andric else if (const auto *DefE = dyn_cast<CXXDefaultInitExpr>(S)) 19810b57cec5SDimitry Andric ArgE = DefE->getExpr(); 19820b57cec5SDimitry Andric else 19830b57cec5SDimitry Andric llvm_unreachable("unknown constant wrapper kind"); 19840b57cec5SDimitry Andric 19850b57cec5SDimitry Andric bool IsTemporary = false; 19860b57cec5SDimitry Andric if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(ArgE)) { 1987480093f4SDimitry Andric ArgE = MTE->getSubExpr(); 19880b57cec5SDimitry Andric IsTemporary = true; 19890b57cec5SDimitry Andric } 19900b57cec5SDimitry Andric 1991bdd1243dSDimitry Andric std::optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE); 19920b57cec5SDimitry Andric if (!ConstantVal) 19930b57cec5SDimitry Andric ConstantVal = UnknownVal(); 19940b57cec5SDimitry Andric 19950b57cec5SDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 19960b57cec5SDimitry Andric for (const auto I : PreVisit) { 19970b57cec5SDimitry Andric ProgramStateRef State = I->getState(); 19980b57cec5SDimitry Andric State = State->BindExpr(S, LCtx, *ConstantVal); 19990b57cec5SDimitry Andric if (IsTemporary) 20000b57cec5SDimitry Andric State = createTemporaryRegionIfNeeded(State, LCtx, 20010b57cec5SDimitry Andric cast<Expr>(S), 20020b57cec5SDimitry Andric cast<Expr>(S)); 20030b57cec5SDimitry Andric Bldr2.generateNode(S, I, State); 20040b57cec5SDimitry Andric } 20050b57cec5SDimitry Andric 20060b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); 20070b57cec5SDimitry Andric Bldr.addNodes(Dst); 20080b57cec5SDimitry Andric break; 20090b57cec5SDimitry Andric } 20100b57cec5SDimitry Andric 20110b57cec5SDimitry Andric // Cases we evaluate as opaque expressions, conjuring a symbol. 20120b57cec5SDimitry Andric case Stmt::CXXStdInitializerListExprClass: 20130b57cec5SDimitry Andric case Expr::ObjCArrayLiteralClass: 20140b57cec5SDimitry Andric case Expr::ObjCDictionaryLiteralClass: 20150b57cec5SDimitry Andric case Expr::ObjCBoxedExprClass: { 20160b57cec5SDimitry Andric Bldr.takeNodes(Pred); 20170b57cec5SDimitry Andric 20180b57cec5SDimitry Andric ExplodedNodeSet preVisit; 20190b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this); 20200b57cec5SDimitry Andric 20210b57cec5SDimitry Andric ExplodedNodeSet Tmp; 20220b57cec5SDimitry Andric StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx); 20230b57cec5SDimitry Andric 20240b57cec5SDimitry Andric const auto *Ex = cast<Expr>(S); 20250b57cec5SDimitry Andric QualType resultType = Ex->getType(); 20260b57cec5SDimitry Andric 20270b57cec5SDimitry Andric for (const auto N : preVisit) { 20280b57cec5SDimitry Andric const LocationContext *LCtx = N->getLocationContext(); 20290b57cec5SDimitry Andric SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, 20300b57cec5SDimitry Andric resultType, 20310b57cec5SDimitry Andric currBldrCtx->blockCount()); 20320b57cec5SDimitry Andric ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, result); 20330b57cec5SDimitry Andric 20340b57cec5SDimitry Andric // Escape pointers passed into the list, unless it's an ObjC boxed 20350b57cec5SDimitry Andric // expression which is not a boxable C structure. 20360b57cec5SDimitry Andric if (!(isa<ObjCBoxedExpr>(Ex) && 20370b57cec5SDimitry Andric !cast<ObjCBoxedExpr>(Ex)->getSubExpr() 20380b57cec5SDimitry Andric ->getType()->isRecordType())) 20390b57cec5SDimitry Andric for (auto Child : Ex->children()) { 20400b57cec5SDimitry Andric assert(Child); 20410b57cec5SDimitry Andric SVal Val = State->getSVal(Child, LCtx); 2042480093f4SDimitry Andric State = escapeValues(State, Val, PSK_EscapeOther); 20430b57cec5SDimitry Andric } 20440b57cec5SDimitry Andric 20450b57cec5SDimitry Andric Bldr2.generateNode(S, N, State); 20460b57cec5SDimitry Andric } 20470b57cec5SDimitry Andric 20480b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); 20490b57cec5SDimitry Andric Bldr.addNodes(Dst); 20500b57cec5SDimitry Andric break; 20510b57cec5SDimitry Andric } 20520b57cec5SDimitry Andric 20530b57cec5SDimitry Andric case Stmt::ArraySubscriptExprClass: 20540b57cec5SDimitry Andric Bldr.takeNodes(Pred); 20550b57cec5SDimitry Andric VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst); 20560b57cec5SDimitry Andric Bldr.addNodes(Dst); 20570b57cec5SDimitry Andric break; 20580b57cec5SDimitry Andric 20595ffd83dbSDimitry Andric case Stmt::MatrixSubscriptExprClass: 20605ffd83dbSDimitry Andric llvm_unreachable("Support for MatrixSubscriptExpr is not implemented."); 20615ffd83dbSDimitry Andric break; 20625ffd83dbSDimitry Andric 20630fca6ea1SDimitry Andric case Stmt::GCCAsmStmtClass: { 20640b57cec5SDimitry Andric Bldr.takeNodes(Pred); 20650fca6ea1SDimitry Andric ExplodedNodeSet PreVisit; 20660fca6ea1SDimitry Andric getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); 20670fca6ea1SDimitry Andric ExplodedNodeSet PostVisit; 20680fca6ea1SDimitry Andric for (ExplodedNode *const N : PreVisit) 20690fca6ea1SDimitry Andric VisitGCCAsmStmt(cast<GCCAsmStmt>(S), N, PostVisit); 20700fca6ea1SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this); 20710b57cec5SDimitry Andric Bldr.addNodes(Dst); 20720b57cec5SDimitry Andric break; 20730fca6ea1SDimitry Andric } 20740b57cec5SDimitry Andric 20750b57cec5SDimitry Andric case Stmt::MSAsmStmtClass: 20760b57cec5SDimitry Andric Bldr.takeNodes(Pred); 20770b57cec5SDimitry Andric VisitMSAsmStmt(cast<MSAsmStmt>(S), Pred, Dst); 20780b57cec5SDimitry Andric Bldr.addNodes(Dst); 20790b57cec5SDimitry Andric break; 20800b57cec5SDimitry Andric 20810b57cec5SDimitry Andric case Stmt::BlockExprClass: 20820b57cec5SDimitry Andric Bldr.takeNodes(Pred); 20830b57cec5SDimitry Andric VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst); 20840b57cec5SDimitry Andric Bldr.addNodes(Dst); 20850b57cec5SDimitry Andric break; 20860b57cec5SDimitry Andric 20870b57cec5SDimitry Andric case Stmt::LambdaExprClass: 20880b57cec5SDimitry Andric if (AMgr.options.ShouldInlineLambdas) { 20890b57cec5SDimitry Andric Bldr.takeNodes(Pred); 20900b57cec5SDimitry Andric VisitLambdaExpr(cast<LambdaExpr>(S), Pred, Dst); 20910b57cec5SDimitry Andric Bldr.addNodes(Dst); 20920b57cec5SDimitry Andric } else { 20930b57cec5SDimitry Andric const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); 20940b57cec5SDimitry Andric Engine.addAbortedBlock(node, currBldrCtx->getBlock()); 20950b57cec5SDimitry Andric } 20960b57cec5SDimitry Andric break; 20970b57cec5SDimitry Andric 20980b57cec5SDimitry Andric case Stmt::BinaryOperatorClass: { 20990b57cec5SDimitry Andric const auto *B = cast<BinaryOperator>(S); 21000b57cec5SDimitry Andric if (B->isLogicalOp()) { 21010b57cec5SDimitry Andric Bldr.takeNodes(Pred); 21020b57cec5SDimitry Andric VisitLogicalExpr(B, Pred, Dst); 21030b57cec5SDimitry Andric Bldr.addNodes(Dst); 21040b57cec5SDimitry Andric break; 21050b57cec5SDimitry Andric } 21060b57cec5SDimitry Andric else if (B->getOpcode() == BO_Comma) { 21070b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 21080b57cec5SDimitry Andric Bldr.generateNode(B, Pred, 21090b57cec5SDimitry Andric state->BindExpr(B, Pred->getLocationContext(), 21100b57cec5SDimitry Andric state->getSVal(B->getRHS(), 21110b57cec5SDimitry Andric Pred->getLocationContext()))); 21120b57cec5SDimitry Andric break; 21130b57cec5SDimitry Andric } 21140b57cec5SDimitry Andric 21150b57cec5SDimitry Andric Bldr.takeNodes(Pred); 21160b57cec5SDimitry Andric 21170b57cec5SDimitry Andric if (AMgr.options.ShouldEagerlyAssume && 21180b57cec5SDimitry Andric (B->isRelationalOp() || B->isEqualityOp())) { 21190b57cec5SDimitry Andric ExplodedNodeSet Tmp; 21200b57cec5SDimitry Andric VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp); 21210b57cec5SDimitry Andric evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S)); 21220b57cec5SDimitry Andric } 21230b57cec5SDimitry Andric else 21240b57cec5SDimitry Andric VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); 21250b57cec5SDimitry Andric 21260b57cec5SDimitry Andric Bldr.addNodes(Dst); 21270b57cec5SDimitry Andric break; 21280b57cec5SDimitry Andric } 21290b57cec5SDimitry Andric 21300b57cec5SDimitry Andric case Stmt::CXXOperatorCallExprClass: { 21310b57cec5SDimitry Andric const auto *OCE = cast<CXXOperatorCallExpr>(S); 21320b57cec5SDimitry Andric 21330b57cec5SDimitry Andric // For instance method operators, make sure the 'this' argument has a 21340b57cec5SDimitry Andric // valid region. 21350b57cec5SDimitry Andric const Decl *Callee = OCE->getCalleeDecl(); 21360b57cec5SDimitry Andric if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) { 21375f757f3fSDimitry Andric if (MD->isImplicitObjectMemberFunction()) { 21380b57cec5SDimitry Andric ProgramStateRef State = Pred->getState(); 21390b57cec5SDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 21400b57cec5SDimitry Andric ProgramStateRef NewState = 21410b57cec5SDimitry Andric createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); 21420b57cec5SDimitry Andric if (NewState != State) { 21430b57cec5SDimitry Andric Pred = Bldr.generateNode(OCE, Pred, NewState, /*tag=*/nullptr, 21440b57cec5SDimitry Andric ProgramPoint::PreStmtKind); 21450b57cec5SDimitry Andric // Did we cache out? 21460b57cec5SDimitry Andric if (!Pred) 21470b57cec5SDimitry Andric break; 21480b57cec5SDimitry Andric } 21490b57cec5SDimitry Andric } 21500b57cec5SDimitry Andric } 2151bdd1243dSDimitry Andric [[fallthrough]]; 21520b57cec5SDimitry Andric } 21530b57cec5SDimitry Andric 21540b57cec5SDimitry Andric case Stmt::CallExprClass: 21550b57cec5SDimitry Andric case Stmt::CXXMemberCallExprClass: 21560b57cec5SDimitry Andric case Stmt::UserDefinedLiteralClass: 21570b57cec5SDimitry Andric Bldr.takeNodes(Pred); 21580b57cec5SDimitry Andric VisitCallExpr(cast<CallExpr>(S), Pred, Dst); 21590b57cec5SDimitry Andric Bldr.addNodes(Dst); 21600b57cec5SDimitry Andric break; 21610b57cec5SDimitry Andric 21620b57cec5SDimitry Andric case Stmt::CXXCatchStmtClass: 21630b57cec5SDimitry Andric Bldr.takeNodes(Pred); 21640b57cec5SDimitry Andric VisitCXXCatchStmt(cast<CXXCatchStmt>(S), Pred, Dst); 21650b57cec5SDimitry Andric Bldr.addNodes(Dst); 21660b57cec5SDimitry Andric break; 21670b57cec5SDimitry Andric 21680b57cec5SDimitry Andric case Stmt::CXXTemporaryObjectExprClass: 21690b57cec5SDimitry Andric case Stmt::CXXConstructExprClass: 21700b57cec5SDimitry Andric Bldr.takeNodes(Pred); 21710b57cec5SDimitry Andric VisitCXXConstructExpr(cast<CXXConstructExpr>(S), Pred, Dst); 21720b57cec5SDimitry Andric Bldr.addNodes(Dst); 21730b57cec5SDimitry Andric break; 21740b57cec5SDimitry Andric 21755ffd83dbSDimitry Andric case Stmt::CXXInheritedCtorInitExprClass: 21765ffd83dbSDimitry Andric Bldr.takeNodes(Pred); 21775ffd83dbSDimitry Andric VisitCXXInheritedCtorInitExpr(cast<CXXInheritedCtorInitExpr>(S), Pred, 21785ffd83dbSDimitry Andric Dst); 21795ffd83dbSDimitry Andric Bldr.addNodes(Dst); 21805ffd83dbSDimitry Andric break; 21815ffd83dbSDimitry Andric 21820b57cec5SDimitry Andric case Stmt::CXXNewExprClass: { 21830b57cec5SDimitry Andric Bldr.takeNodes(Pred); 21840b57cec5SDimitry Andric 21850b57cec5SDimitry Andric ExplodedNodeSet PreVisit; 21860b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); 21870b57cec5SDimitry Andric 21880b57cec5SDimitry Andric ExplodedNodeSet PostVisit; 21890b57cec5SDimitry Andric for (const auto i : PreVisit) 21900b57cec5SDimitry Andric VisitCXXNewExpr(cast<CXXNewExpr>(S), i, PostVisit); 21910b57cec5SDimitry Andric 21920b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this); 21930b57cec5SDimitry Andric Bldr.addNodes(Dst); 21940b57cec5SDimitry Andric break; 21950b57cec5SDimitry Andric } 21960b57cec5SDimitry Andric 21970b57cec5SDimitry Andric case Stmt::CXXDeleteExprClass: { 21980b57cec5SDimitry Andric Bldr.takeNodes(Pred); 21990b57cec5SDimitry Andric ExplodedNodeSet PreVisit; 22000b57cec5SDimitry Andric const auto *CDE = cast<CXXDeleteExpr>(S); 22010b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); 22025ffd83dbSDimitry Andric ExplodedNodeSet PostVisit; 22035ffd83dbSDimitry Andric getCheckerManager().runCheckersForPostStmt(PostVisit, PreVisit, S, *this); 22040b57cec5SDimitry Andric 22055ffd83dbSDimitry Andric for (const auto i : PostVisit) 22060b57cec5SDimitry Andric VisitCXXDeleteExpr(CDE, i, Dst); 22070b57cec5SDimitry Andric 22080b57cec5SDimitry Andric Bldr.addNodes(Dst); 22090b57cec5SDimitry Andric break; 22100b57cec5SDimitry Andric } 22110b57cec5SDimitry Andric // FIXME: ChooseExpr is really a constant. We need to fix 22120b57cec5SDimitry Andric // the CFG do not model them as explicit control-flow. 22130b57cec5SDimitry Andric 22140b57cec5SDimitry Andric case Stmt::ChooseExprClass: { // __builtin_choose_expr 22150b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22160b57cec5SDimitry Andric const auto *C = cast<ChooseExpr>(S); 22170b57cec5SDimitry Andric VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); 22180b57cec5SDimitry Andric Bldr.addNodes(Dst); 22190b57cec5SDimitry Andric break; 22200b57cec5SDimitry Andric } 22210b57cec5SDimitry Andric 22220b57cec5SDimitry Andric case Stmt::CompoundAssignOperatorClass: 22230b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22240b57cec5SDimitry Andric VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); 22250b57cec5SDimitry Andric Bldr.addNodes(Dst); 22260b57cec5SDimitry Andric break; 22270b57cec5SDimitry Andric 22280b57cec5SDimitry Andric case Stmt::CompoundLiteralExprClass: 22290b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22300b57cec5SDimitry Andric VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst); 22310b57cec5SDimitry Andric Bldr.addNodes(Dst); 22320b57cec5SDimitry Andric break; 22330b57cec5SDimitry Andric 22340b57cec5SDimitry Andric case Stmt::BinaryConditionalOperatorClass: 22350b57cec5SDimitry Andric case Stmt::ConditionalOperatorClass: { // '?' operator 22360b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22370b57cec5SDimitry Andric const auto *C = cast<AbstractConditionalOperator>(S); 22380b57cec5SDimitry Andric VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst); 22390b57cec5SDimitry Andric Bldr.addNodes(Dst); 22400b57cec5SDimitry Andric break; 22410b57cec5SDimitry Andric } 22420b57cec5SDimitry Andric 22430b57cec5SDimitry Andric case Stmt::CXXThisExprClass: 22440b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22450b57cec5SDimitry Andric VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst); 22460b57cec5SDimitry Andric Bldr.addNodes(Dst); 22470b57cec5SDimitry Andric break; 22480b57cec5SDimitry Andric 22490b57cec5SDimitry Andric case Stmt::DeclRefExprClass: { 22500b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22510b57cec5SDimitry Andric const auto *DE = cast<DeclRefExpr>(S); 22520b57cec5SDimitry Andric VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst); 22530b57cec5SDimitry Andric Bldr.addNodes(Dst); 22540b57cec5SDimitry Andric break; 22550b57cec5SDimitry Andric } 22560b57cec5SDimitry Andric 22570b57cec5SDimitry Andric case Stmt::DeclStmtClass: 22580b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22590b57cec5SDimitry Andric VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst); 22600b57cec5SDimitry Andric Bldr.addNodes(Dst); 22610b57cec5SDimitry Andric break; 22620b57cec5SDimitry Andric 22630b57cec5SDimitry Andric case Stmt::ImplicitCastExprClass: 22640b57cec5SDimitry Andric case Stmt::CStyleCastExprClass: 22650b57cec5SDimitry Andric case Stmt::CXXStaticCastExprClass: 22660b57cec5SDimitry Andric case Stmt::CXXDynamicCastExprClass: 22670b57cec5SDimitry Andric case Stmt::CXXReinterpretCastExprClass: 22680b57cec5SDimitry Andric case Stmt::CXXConstCastExprClass: 22690b57cec5SDimitry Andric case Stmt::CXXFunctionalCastExprClass: 22700b57cec5SDimitry Andric case Stmt::BuiltinBitCastExprClass: 22715ffd83dbSDimitry Andric case Stmt::ObjCBridgedCastExprClass: 22725ffd83dbSDimitry Andric case Stmt::CXXAddrspaceCastExprClass: { 22730b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22740b57cec5SDimitry Andric const auto *C = cast<CastExpr>(S); 22750b57cec5SDimitry Andric ExplodedNodeSet dstExpr; 22760b57cec5SDimitry Andric VisitCast(C, C->getSubExpr(), Pred, dstExpr); 22770b57cec5SDimitry Andric 22780b57cec5SDimitry Andric // Handle the postvisit checks. 22790b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this); 22800b57cec5SDimitry Andric Bldr.addNodes(Dst); 22810b57cec5SDimitry Andric break; 22820b57cec5SDimitry Andric } 22830b57cec5SDimitry Andric 22840b57cec5SDimitry Andric case Expr::MaterializeTemporaryExprClass: { 22850b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22860b57cec5SDimitry Andric const auto *MTE = cast<MaterializeTemporaryExpr>(S); 22870b57cec5SDimitry Andric ExplodedNodeSet dstPrevisit; 22880b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, MTE, *this); 22890b57cec5SDimitry Andric ExplodedNodeSet dstExpr; 22900b57cec5SDimitry Andric for (const auto i : dstPrevisit) 22910b57cec5SDimitry Andric CreateCXXTemporaryObject(MTE, i, dstExpr); 22920b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, MTE, *this); 22930b57cec5SDimitry Andric Bldr.addNodes(Dst); 22940b57cec5SDimitry Andric break; 22950b57cec5SDimitry Andric } 22960b57cec5SDimitry Andric 22970b57cec5SDimitry Andric case Stmt::InitListExprClass: 22980b57cec5SDimitry Andric Bldr.takeNodes(Pred); 22990b57cec5SDimitry Andric VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst); 23000b57cec5SDimitry Andric Bldr.addNodes(Dst); 23010b57cec5SDimitry Andric break; 23020b57cec5SDimitry Andric 23030b57cec5SDimitry Andric case Stmt::MemberExprClass: 23040b57cec5SDimitry Andric Bldr.takeNodes(Pred); 23050b57cec5SDimitry Andric VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst); 23060b57cec5SDimitry Andric Bldr.addNodes(Dst); 23070b57cec5SDimitry Andric break; 23080b57cec5SDimitry Andric 23090b57cec5SDimitry Andric case Stmt::AtomicExprClass: 23100b57cec5SDimitry Andric Bldr.takeNodes(Pred); 23110b57cec5SDimitry Andric VisitAtomicExpr(cast<AtomicExpr>(S), Pred, Dst); 23120b57cec5SDimitry Andric Bldr.addNodes(Dst); 23130b57cec5SDimitry Andric break; 23140b57cec5SDimitry Andric 23150b57cec5SDimitry Andric case Stmt::ObjCIvarRefExprClass: 23160b57cec5SDimitry Andric Bldr.takeNodes(Pred); 23170b57cec5SDimitry Andric VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst); 23180b57cec5SDimitry Andric Bldr.addNodes(Dst); 23190b57cec5SDimitry Andric break; 23200b57cec5SDimitry Andric 23210b57cec5SDimitry Andric case Stmt::ObjCForCollectionStmtClass: 23220b57cec5SDimitry Andric Bldr.takeNodes(Pred); 23230b57cec5SDimitry Andric VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst); 23240b57cec5SDimitry Andric Bldr.addNodes(Dst); 23250b57cec5SDimitry Andric break; 23260b57cec5SDimitry Andric 23270b57cec5SDimitry Andric case Stmt::ObjCMessageExprClass: 23280b57cec5SDimitry Andric Bldr.takeNodes(Pred); 23290b57cec5SDimitry Andric VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst); 23300b57cec5SDimitry Andric Bldr.addNodes(Dst); 23310b57cec5SDimitry Andric break; 23320b57cec5SDimitry Andric 23330b57cec5SDimitry Andric case Stmt::ObjCAtThrowStmtClass: 23340b57cec5SDimitry Andric case Stmt::CXXThrowExprClass: 23350b57cec5SDimitry Andric // FIXME: This is not complete. We basically treat @throw as 23360b57cec5SDimitry Andric // an abort. 23370b57cec5SDimitry Andric Bldr.generateSink(S, Pred, Pred->getState()); 23380b57cec5SDimitry Andric break; 23390b57cec5SDimitry Andric 23400b57cec5SDimitry Andric case Stmt::ReturnStmtClass: 23410b57cec5SDimitry Andric Bldr.takeNodes(Pred); 23420b57cec5SDimitry Andric VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst); 23430b57cec5SDimitry Andric Bldr.addNodes(Dst); 23440b57cec5SDimitry Andric break; 23450b57cec5SDimitry Andric 23460b57cec5SDimitry Andric case Stmt::OffsetOfExprClass: { 23470b57cec5SDimitry Andric Bldr.takeNodes(Pred); 23480b57cec5SDimitry Andric ExplodedNodeSet PreVisit; 23490b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); 23500b57cec5SDimitry Andric 23510b57cec5SDimitry Andric ExplodedNodeSet PostVisit; 23520b57cec5SDimitry Andric for (const auto Node : PreVisit) 23530b57cec5SDimitry Andric VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Node, PostVisit); 23540b57cec5SDimitry Andric 23550b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this); 23560b57cec5SDimitry Andric Bldr.addNodes(Dst); 23570b57cec5SDimitry Andric break; 23580b57cec5SDimitry Andric } 23590b57cec5SDimitry Andric 23600b57cec5SDimitry Andric case Stmt::UnaryExprOrTypeTraitExprClass: 23610b57cec5SDimitry Andric Bldr.takeNodes(Pred); 23620b57cec5SDimitry Andric VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S), 23630b57cec5SDimitry Andric Pred, Dst); 23640b57cec5SDimitry Andric Bldr.addNodes(Dst); 23650b57cec5SDimitry Andric break; 23660b57cec5SDimitry Andric 23670b57cec5SDimitry Andric case Stmt::StmtExprClass: { 23680b57cec5SDimitry Andric const auto *SE = cast<StmtExpr>(S); 23690b57cec5SDimitry Andric 23700b57cec5SDimitry Andric if (SE->getSubStmt()->body_empty()) { 23710b57cec5SDimitry Andric // Empty statement expression. 23720b57cec5SDimitry Andric assert(SE->getType() == getContext().VoidTy 23730b57cec5SDimitry Andric && "Empty statement expression must have void type."); 23740b57cec5SDimitry Andric break; 23750b57cec5SDimitry Andric } 23760b57cec5SDimitry Andric 23770b57cec5SDimitry Andric if (const auto *LastExpr = 23780b57cec5SDimitry Andric dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) { 23790b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 23800b57cec5SDimitry Andric Bldr.generateNode(SE, Pred, 23810b57cec5SDimitry Andric state->BindExpr(SE, Pred->getLocationContext(), 23820b57cec5SDimitry Andric state->getSVal(LastExpr, 23830b57cec5SDimitry Andric Pred->getLocationContext()))); 23840b57cec5SDimitry Andric } 23850b57cec5SDimitry Andric break; 23860b57cec5SDimitry Andric } 23870b57cec5SDimitry Andric 23880b57cec5SDimitry Andric case Stmt::UnaryOperatorClass: { 23890b57cec5SDimitry Andric Bldr.takeNodes(Pred); 23900b57cec5SDimitry Andric const auto *U = cast<UnaryOperator>(S); 23910b57cec5SDimitry Andric if (AMgr.options.ShouldEagerlyAssume && (U->getOpcode() == UO_LNot)) { 23920b57cec5SDimitry Andric ExplodedNodeSet Tmp; 23930b57cec5SDimitry Andric VisitUnaryOperator(U, Pred, Tmp); 23940b57cec5SDimitry Andric evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U); 23950b57cec5SDimitry Andric } 23960b57cec5SDimitry Andric else 23970b57cec5SDimitry Andric VisitUnaryOperator(U, Pred, Dst); 23980b57cec5SDimitry Andric Bldr.addNodes(Dst); 23990b57cec5SDimitry Andric break; 24000b57cec5SDimitry Andric } 24010b57cec5SDimitry Andric 24020b57cec5SDimitry Andric case Stmt::PseudoObjectExprClass: { 24030b57cec5SDimitry Andric Bldr.takeNodes(Pred); 24040b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 24050b57cec5SDimitry Andric const auto *PE = cast<PseudoObjectExpr>(S); 24060b57cec5SDimitry Andric if (const Expr *Result = PE->getResultExpr()) { 24070b57cec5SDimitry Andric SVal V = state->getSVal(Result, Pred->getLocationContext()); 24080b57cec5SDimitry Andric Bldr.generateNode(S, Pred, 24090b57cec5SDimitry Andric state->BindExpr(S, Pred->getLocationContext(), V)); 24100b57cec5SDimitry Andric } 24110b57cec5SDimitry Andric else 24120b57cec5SDimitry Andric Bldr.generateNode(S, Pred, 24130b57cec5SDimitry Andric state->BindExpr(S, Pred->getLocationContext(), 24140b57cec5SDimitry Andric UnknownVal())); 24150b57cec5SDimitry Andric 24160b57cec5SDimitry Andric Bldr.addNodes(Dst); 24170b57cec5SDimitry Andric break; 24180b57cec5SDimitry Andric } 24195ffd83dbSDimitry Andric 24205ffd83dbSDimitry Andric case Expr::ObjCIndirectCopyRestoreExprClass: { 24215ffd83dbSDimitry Andric // ObjCIndirectCopyRestoreExpr implies passing a temporary for 24225ffd83dbSDimitry Andric // correctness of lifetime management. Due to limited analysis 24235ffd83dbSDimitry Andric // of ARC, this is implemented as direct arg passing. 24245ffd83dbSDimitry Andric Bldr.takeNodes(Pred); 24255ffd83dbSDimitry Andric ProgramStateRef state = Pred->getState(); 24265ffd83dbSDimitry Andric const auto *OIE = cast<ObjCIndirectCopyRestoreExpr>(S); 24275ffd83dbSDimitry Andric const Expr *E = OIE->getSubExpr(); 24285ffd83dbSDimitry Andric SVal V = state->getSVal(E, Pred->getLocationContext()); 24295ffd83dbSDimitry Andric Bldr.generateNode(S, Pred, 24305ffd83dbSDimitry Andric state->BindExpr(S, Pred->getLocationContext(), V)); 24315ffd83dbSDimitry Andric Bldr.addNodes(Dst); 24325ffd83dbSDimitry Andric break; 24335ffd83dbSDimitry Andric } 24340b57cec5SDimitry Andric } 24350b57cec5SDimitry Andric } 24360b57cec5SDimitry Andric 24370b57cec5SDimitry Andric bool ExprEngine::replayWithoutInlining(ExplodedNode *N, 24380b57cec5SDimitry Andric const LocationContext *CalleeLC) { 24390b57cec5SDimitry Andric const StackFrameContext *CalleeSF = CalleeLC->getStackFrame(); 24400b57cec5SDimitry Andric const StackFrameContext *CallerSF = CalleeSF->getParent()->getStackFrame(); 24410b57cec5SDimitry Andric assert(CalleeSF && CallerSF); 24420b57cec5SDimitry Andric ExplodedNode *BeforeProcessingCall = nullptr; 24430b57cec5SDimitry Andric const Stmt *CE = CalleeSF->getCallSite(); 24440b57cec5SDimitry Andric 24450b57cec5SDimitry Andric // Find the first node before we started processing the call expression. 24460b57cec5SDimitry Andric while (N) { 24470b57cec5SDimitry Andric ProgramPoint L = N->getLocation(); 24480b57cec5SDimitry Andric BeforeProcessingCall = N; 24490b57cec5SDimitry Andric N = N->pred_empty() ? nullptr : *(N->pred_begin()); 24500b57cec5SDimitry Andric 24510b57cec5SDimitry Andric // Skip the nodes corresponding to the inlined code. 24520b57cec5SDimitry Andric if (L.getStackFrame() != CallerSF) 24530b57cec5SDimitry Andric continue; 24540b57cec5SDimitry Andric // We reached the caller. Find the node right before we started 24550b57cec5SDimitry Andric // processing the call. 24560b57cec5SDimitry Andric if (L.isPurgeKind()) 24570b57cec5SDimitry Andric continue; 24580b57cec5SDimitry Andric if (L.getAs<PreImplicitCall>()) 24590b57cec5SDimitry Andric continue; 24600b57cec5SDimitry Andric if (L.getAs<CallEnter>()) 24610b57cec5SDimitry Andric continue; 2462bdd1243dSDimitry Andric if (std::optional<StmtPoint> SP = L.getAs<StmtPoint>()) 24630b57cec5SDimitry Andric if (SP->getStmt() == CE) 24640b57cec5SDimitry Andric continue; 24650b57cec5SDimitry Andric break; 24660b57cec5SDimitry Andric } 24670b57cec5SDimitry Andric 24680b57cec5SDimitry Andric if (!BeforeProcessingCall) 24690b57cec5SDimitry Andric return false; 24700b57cec5SDimitry Andric 24710b57cec5SDimitry Andric // TODO: Clean up the unneeded nodes. 24720b57cec5SDimitry Andric 24730b57cec5SDimitry Andric // Build an Epsilon node from which we will restart the analyzes. 24740b57cec5SDimitry Andric // Note that CE is permitted to be NULL! 2475bdd1243dSDimitry Andric static SimpleProgramPointTag PT("ExprEngine", "Replay without inlining"); 2476bdd1243dSDimitry Andric ProgramPoint NewNodeLoc = EpsilonPoint( 2477bdd1243dSDimitry Andric BeforeProcessingCall->getLocationContext(), CE, nullptr, &PT); 24780b57cec5SDimitry Andric // Add the special flag to GDM to signal retrying with no inlining. 24790b57cec5SDimitry Andric // Note, changing the state ensures that we are not going to cache out. 24800b57cec5SDimitry Andric ProgramStateRef NewNodeState = BeforeProcessingCall->getState(); 24810b57cec5SDimitry Andric NewNodeState = 24820b57cec5SDimitry Andric NewNodeState->set<ReplayWithoutInlining>(const_cast<Stmt *>(CE)); 24830b57cec5SDimitry Andric 24840b57cec5SDimitry Andric // Make the new node a successor of BeforeProcessingCall. 24850b57cec5SDimitry Andric bool IsNew = false; 24860b57cec5SDimitry Andric ExplodedNode *NewNode = G.getNode(NewNodeLoc, NewNodeState, false, &IsNew); 24870b57cec5SDimitry Andric // We cached out at this point. Caching out is common due to us backtracking 24880b57cec5SDimitry Andric // from the inlined function, which might spawn several paths. 24890b57cec5SDimitry Andric if (!IsNew) 24900b57cec5SDimitry Andric return true; 24910b57cec5SDimitry Andric 24920b57cec5SDimitry Andric NewNode->addPredecessor(BeforeProcessingCall, G); 24930b57cec5SDimitry Andric 24940b57cec5SDimitry Andric // Add the new node to the work list. 24950b57cec5SDimitry Andric Engine.enqueueStmtNode(NewNode, CalleeSF->getCallSiteBlock(), 24960b57cec5SDimitry Andric CalleeSF->getIndex()); 24970b57cec5SDimitry Andric NumTimesRetriedWithoutInlining++; 24980b57cec5SDimitry Andric return true; 24990b57cec5SDimitry Andric } 25000b57cec5SDimitry Andric 25010b57cec5SDimitry Andric /// Block entrance. (Update counters). 25020b57cec5SDimitry Andric void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, 25030b57cec5SDimitry Andric NodeBuilderWithSinks &nodeBuilder, 25040b57cec5SDimitry Andric ExplodedNode *Pred) { 25050b57cec5SDimitry Andric PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); 25060b57cec5SDimitry Andric // If we reach a loop which has a known bound (and meets 25070b57cec5SDimitry Andric // other constraints) then consider completely unrolling it. 25080b57cec5SDimitry Andric if(AMgr.options.ShouldUnrollLoops) { 25090b57cec5SDimitry Andric unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath; 25100b57cec5SDimitry Andric const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt(); 25110b57cec5SDimitry Andric if (Term) { 25120b57cec5SDimitry Andric ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(), 25130b57cec5SDimitry Andric Pred, maxBlockVisitOnPath); 25140b57cec5SDimitry Andric if (NewState != Pred->getState()) { 25150b57cec5SDimitry Andric ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred); 25160b57cec5SDimitry Andric if (!UpdatedNode) 25170b57cec5SDimitry Andric return; 25180b57cec5SDimitry Andric Pred = UpdatedNode; 25190b57cec5SDimitry Andric } 25200b57cec5SDimitry Andric } 25210b57cec5SDimitry Andric // Is we are inside an unrolled loop then no need the check the counters. 25220b57cec5SDimitry Andric if(isUnrolledState(Pred->getState())) 25230b57cec5SDimitry Andric return; 25240b57cec5SDimitry Andric } 25250b57cec5SDimitry Andric 25260b57cec5SDimitry Andric // If this block is terminated by a loop and it has already been visited the 25270b57cec5SDimitry Andric // maximum number of times, widen the loop. 25280b57cec5SDimitry Andric unsigned int BlockCount = nodeBuilder.getContext().blockCount(); 25290b57cec5SDimitry Andric if (BlockCount == AMgr.options.maxBlockVisitOnPath - 1 && 25300b57cec5SDimitry Andric AMgr.options.ShouldWidenLoops) { 25310b57cec5SDimitry Andric const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt(); 25325f757f3fSDimitry Andric if (!isa_and_nonnull<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(Term)) 25330b57cec5SDimitry Andric return; 25340b57cec5SDimitry Andric // Widen. 25350b57cec5SDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 25360b57cec5SDimitry Andric ProgramStateRef WidenedState = 25370b57cec5SDimitry Andric getWidenedLoopState(Pred->getState(), LCtx, BlockCount, Term); 25380b57cec5SDimitry Andric nodeBuilder.generateNode(WidenedState, Pred); 25390b57cec5SDimitry Andric return; 25400b57cec5SDimitry Andric } 25410b57cec5SDimitry Andric 25420b57cec5SDimitry Andric // FIXME: Refactor this into a checker. 25430b57cec5SDimitry Andric if (BlockCount >= AMgr.options.maxBlockVisitOnPath) { 25440b57cec5SDimitry Andric static SimpleProgramPointTag tag(TagProviderName, "Block count exceeded"); 25450b57cec5SDimitry Andric const ExplodedNode *Sink = 25460b57cec5SDimitry Andric nodeBuilder.generateSink(Pred->getState(), Pred, &tag); 25470b57cec5SDimitry Andric 25480b57cec5SDimitry Andric // Check if we stopped at the top level function or not. 25490b57cec5SDimitry Andric // Root node should have the location context of the top most function. 25500b57cec5SDimitry Andric const LocationContext *CalleeLC = Pred->getLocation().getLocationContext(); 25510b57cec5SDimitry Andric const LocationContext *CalleeSF = CalleeLC->getStackFrame(); 25520b57cec5SDimitry Andric const LocationContext *RootLC = 25530b57cec5SDimitry Andric (*G.roots_begin())->getLocation().getLocationContext(); 25540b57cec5SDimitry Andric if (RootLC->getStackFrame() != CalleeSF) { 25550b57cec5SDimitry Andric Engine.FunctionSummaries->markReachedMaxBlockCount(CalleeSF->getDecl()); 25560b57cec5SDimitry Andric 25570b57cec5SDimitry Andric // Re-run the call evaluation without inlining it, by storing the 25580b57cec5SDimitry Andric // no-inlining policy in the state and enqueuing the new work item on 25590b57cec5SDimitry Andric // the list. Replay should almost never fail. Use the stats to catch it 25600b57cec5SDimitry Andric // if it does. 25610b57cec5SDimitry Andric if ((!AMgr.options.NoRetryExhausted && 25620b57cec5SDimitry Andric replayWithoutInlining(Pred, CalleeLC))) 25630b57cec5SDimitry Andric return; 25640b57cec5SDimitry Andric NumMaxBlockCountReachedInInlined++; 25650b57cec5SDimitry Andric } else 25660b57cec5SDimitry Andric NumMaxBlockCountReached++; 25670b57cec5SDimitry Andric 25680b57cec5SDimitry Andric // Make sink nodes as exhausted(for stats) only if retry failed. 25690b57cec5SDimitry Andric Engine.blocksExhausted.push_back(std::make_pair(L, Sink)); 25700b57cec5SDimitry Andric } 25710b57cec5SDimitry Andric } 25720b57cec5SDimitry Andric 25730b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 25740b57cec5SDimitry Andric // Branch processing. 25750b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 25760b57cec5SDimitry Andric 25770b57cec5SDimitry Andric /// RecoverCastedSymbol - A helper function for ProcessBranch that is used 25780b57cec5SDimitry Andric /// to try to recover some path-sensitivity for casts of symbolic 25790b57cec5SDimitry Andric /// integers that promote their values (which are currently not tracked well). 25800b57cec5SDimitry Andric /// This function returns the SVal bound to Condition->IgnoreCasts if all the 25810b57cec5SDimitry Andric // cast(s) did was sign-extend the original value. 25820b57cec5SDimitry Andric static SVal RecoverCastedSymbol(ProgramStateRef state, 25830b57cec5SDimitry Andric const Stmt *Condition, 25840b57cec5SDimitry Andric const LocationContext *LCtx, 25850b57cec5SDimitry Andric ASTContext &Ctx) { 25860b57cec5SDimitry Andric 25870b57cec5SDimitry Andric const auto *Ex = dyn_cast<Expr>(Condition); 25880b57cec5SDimitry Andric if (!Ex) 25890b57cec5SDimitry Andric return UnknownVal(); 25900b57cec5SDimitry Andric 25910b57cec5SDimitry Andric uint64_t bits = 0; 25920b57cec5SDimitry Andric bool bitsInit = false; 25930b57cec5SDimitry Andric 25940b57cec5SDimitry Andric while (const auto *CE = dyn_cast<CastExpr>(Ex)) { 25950b57cec5SDimitry Andric QualType T = CE->getType(); 25960b57cec5SDimitry Andric 25970b57cec5SDimitry Andric if (!T->isIntegralOrEnumerationType()) 25980b57cec5SDimitry Andric return UnknownVal(); 25990b57cec5SDimitry Andric 26000b57cec5SDimitry Andric uint64_t newBits = Ctx.getTypeSize(T); 26010b57cec5SDimitry Andric if (!bitsInit || newBits < bits) { 26020b57cec5SDimitry Andric bitsInit = true; 26030b57cec5SDimitry Andric bits = newBits; 26040b57cec5SDimitry Andric } 26050b57cec5SDimitry Andric 26060b57cec5SDimitry Andric Ex = CE->getSubExpr(); 26070b57cec5SDimitry Andric } 26080b57cec5SDimitry Andric 26090b57cec5SDimitry Andric // We reached a non-cast. Is it a symbolic value? 26100b57cec5SDimitry Andric QualType T = Ex->getType(); 26110b57cec5SDimitry Andric 26120b57cec5SDimitry Andric if (!bitsInit || !T->isIntegralOrEnumerationType() || 26130b57cec5SDimitry Andric Ctx.getTypeSize(T) > bits) 26140b57cec5SDimitry Andric return UnknownVal(); 26150b57cec5SDimitry Andric 26160b57cec5SDimitry Andric return state->getSVal(Ex, LCtx); 26170b57cec5SDimitry Andric } 26180b57cec5SDimitry Andric 26190b57cec5SDimitry Andric #ifndef NDEBUG 26200b57cec5SDimitry Andric static const Stmt *getRightmostLeaf(const Stmt *Condition) { 26210b57cec5SDimitry Andric while (Condition) { 26220b57cec5SDimitry Andric const auto *BO = dyn_cast<BinaryOperator>(Condition); 26230b57cec5SDimitry Andric if (!BO || !BO->isLogicalOp()) { 26240b57cec5SDimitry Andric return Condition; 26250b57cec5SDimitry Andric } 26260b57cec5SDimitry Andric Condition = BO->getRHS()->IgnoreParens(); 26270b57cec5SDimitry Andric } 26280b57cec5SDimitry Andric return nullptr; 26290b57cec5SDimitry Andric } 26300b57cec5SDimitry Andric #endif 26310b57cec5SDimitry Andric 26320b57cec5SDimitry Andric // Returns the condition the branch at the end of 'B' depends on and whose value 26330b57cec5SDimitry Andric // has been evaluated within 'B'. 26340b57cec5SDimitry Andric // In most cases, the terminator condition of 'B' will be evaluated fully in 26350b57cec5SDimitry Andric // the last statement of 'B'; in those cases, the resolved condition is the 26360b57cec5SDimitry Andric // given 'Condition'. 26370b57cec5SDimitry Andric // If the condition of the branch is a logical binary operator tree, the CFG is 26380b57cec5SDimitry Andric // optimized: in that case, we know that the expression formed by all but the 26390b57cec5SDimitry Andric // rightmost leaf of the logical binary operator tree must be true, and thus 26400b57cec5SDimitry Andric // the branch condition is at this point equivalent to the truth value of that 26410b57cec5SDimitry Andric // rightmost leaf; the CFG block thus only evaluates this rightmost leaf 26420b57cec5SDimitry Andric // expression in its final statement. As the full condition in that case was 26430b57cec5SDimitry Andric // not evaluated, and is thus not in the SVal cache, we need to use that leaf 26440b57cec5SDimitry Andric // expression to evaluate the truth value of the condition in the current state 26450b57cec5SDimitry Andric // space. 26460b57cec5SDimitry Andric static const Stmt *ResolveCondition(const Stmt *Condition, 26470b57cec5SDimitry Andric const CFGBlock *B) { 26480b57cec5SDimitry Andric if (const auto *Ex = dyn_cast<Expr>(Condition)) 26490b57cec5SDimitry Andric Condition = Ex->IgnoreParens(); 26500b57cec5SDimitry Andric 26510b57cec5SDimitry Andric const auto *BO = dyn_cast<BinaryOperator>(Condition); 26520b57cec5SDimitry Andric if (!BO || !BO->isLogicalOp()) 26530b57cec5SDimitry Andric return Condition; 26540b57cec5SDimitry Andric 26550b57cec5SDimitry Andric assert(B->getTerminator().isStmtBranch() && 26560b57cec5SDimitry Andric "Other kinds of branches are handled separately!"); 26570b57cec5SDimitry Andric 26580b57cec5SDimitry Andric // For logical operations, we still have the case where some branches 26590b57cec5SDimitry Andric // use the traditional "merge" approach and others sink the branch 26600b57cec5SDimitry Andric // directly into the basic blocks representing the logical operation. 26610b57cec5SDimitry Andric // We need to distinguish between those two cases here. 26620b57cec5SDimitry Andric 26630b57cec5SDimitry Andric // The invariants are still shifting, but it is possible that the 26640b57cec5SDimitry Andric // last element in a CFGBlock is not a CFGStmt. Look for the last 26650b57cec5SDimitry Andric // CFGStmt as the value of the condition. 266606c3fb27SDimitry Andric for (CFGElement Elem : llvm::reverse(*B)) { 2667bdd1243dSDimitry Andric std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>(); 26680b57cec5SDimitry Andric if (!CS) 26690b57cec5SDimitry Andric continue; 26700b57cec5SDimitry Andric const Stmt *LastStmt = CS->getStmt(); 26710b57cec5SDimitry Andric assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition)); 26720b57cec5SDimitry Andric return LastStmt; 26730b57cec5SDimitry Andric } 26740b57cec5SDimitry Andric llvm_unreachable("could not resolve condition"); 26750b57cec5SDimitry Andric } 26760b57cec5SDimitry Andric 2677e8d8bef9SDimitry Andric using ObjCForLctxPair = 2678e8d8bef9SDimitry Andric std::pair<const ObjCForCollectionStmt *, const LocationContext *>; 2679e8d8bef9SDimitry Andric 2680e8d8bef9SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(ObjCForHasMoreIterations, ObjCForLctxPair, bool) 2681e8d8bef9SDimitry Andric 2682e8d8bef9SDimitry Andric ProgramStateRef ExprEngine::setWhetherHasMoreIteration( 2683e8d8bef9SDimitry Andric ProgramStateRef State, const ObjCForCollectionStmt *O, 2684e8d8bef9SDimitry Andric const LocationContext *LC, bool HasMoreIteraton) { 2685e8d8bef9SDimitry Andric assert(!State->contains<ObjCForHasMoreIterations>({O, LC})); 2686e8d8bef9SDimitry Andric return State->set<ObjCForHasMoreIterations>({O, LC}, HasMoreIteraton); 2687e8d8bef9SDimitry Andric } 2688e8d8bef9SDimitry Andric 2689e8d8bef9SDimitry Andric ProgramStateRef 2690e8d8bef9SDimitry Andric ExprEngine::removeIterationState(ProgramStateRef State, 2691e8d8bef9SDimitry Andric const ObjCForCollectionStmt *O, 2692e8d8bef9SDimitry Andric const LocationContext *LC) { 2693e8d8bef9SDimitry Andric assert(State->contains<ObjCForHasMoreIterations>({O, LC})); 2694e8d8bef9SDimitry Andric return State->remove<ObjCForHasMoreIterations>({O, LC}); 2695e8d8bef9SDimitry Andric } 2696e8d8bef9SDimitry Andric 2697e8d8bef9SDimitry Andric bool ExprEngine::hasMoreIteration(ProgramStateRef State, 2698e8d8bef9SDimitry Andric const ObjCForCollectionStmt *O, 2699e8d8bef9SDimitry Andric const LocationContext *LC) { 2700e8d8bef9SDimitry Andric assert(State->contains<ObjCForHasMoreIterations>({O, LC})); 2701e8d8bef9SDimitry Andric return *State->get<ObjCForHasMoreIterations>({O, LC}); 2702e8d8bef9SDimitry Andric } 2703e8d8bef9SDimitry Andric 2704e8d8bef9SDimitry Andric /// Split the state on whether there are any more iterations left for this loop. 2705bdd1243dSDimitry Andric /// Returns a (HasMoreIteration, HasNoMoreIteration) pair, or std::nullopt when 2706bdd1243dSDimitry Andric /// the acquisition of the loop condition value failed. 2707bdd1243dSDimitry Andric static std::optional<std::pair<ProgramStateRef, ProgramStateRef>> 2708e8d8bef9SDimitry Andric assumeCondition(const Stmt *Condition, ExplodedNode *N) { 2709e8d8bef9SDimitry Andric ProgramStateRef State = N->getState(); 2710e8d8bef9SDimitry Andric if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(Condition)) { 2711e8d8bef9SDimitry Andric bool HasMoreIteraton = 2712e8d8bef9SDimitry Andric ExprEngine::hasMoreIteration(State, ObjCFor, N->getLocationContext()); 2713e8d8bef9SDimitry Andric // Checkers have already ran on branch conditions, so the current 2714e8d8bef9SDimitry Andric // information as to whether the loop has more iteration becomes outdated 2715e8d8bef9SDimitry Andric // after this point. 2716e8d8bef9SDimitry Andric State = ExprEngine::removeIterationState(State, ObjCFor, 2717e8d8bef9SDimitry Andric N->getLocationContext()); 2718e8d8bef9SDimitry Andric if (HasMoreIteraton) 2719e8d8bef9SDimitry Andric return std::pair<ProgramStateRef, ProgramStateRef>{State, nullptr}; 2720e8d8bef9SDimitry Andric else 2721e8d8bef9SDimitry Andric return std::pair<ProgramStateRef, ProgramStateRef>{nullptr, State}; 2722e8d8bef9SDimitry Andric } 2723e8d8bef9SDimitry Andric SVal X = State->getSVal(Condition, N->getLocationContext()); 2724e8d8bef9SDimitry Andric 2725e8d8bef9SDimitry Andric if (X.isUnknownOrUndef()) { 2726e8d8bef9SDimitry Andric // Give it a chance to recover from unknown. 2727e8d8bef9SDimitry Andric if (const auto *Ex = dyn_cast<Expr>(Condition)) { 2728e8d8bef9SDimitry Andric if (Ex->getType()->isIntegralOrEnumerationType()) { 2729e8d8bef9SDimitry Andric // Try to recover some path-sensitivity. Right now casts of symbolic 2730e8d8bef9SDimitry Andric // integers that promote their values are currently not tracked well. 2731e8d8bef9SDimitry Andric // If 'Condition' is such an expression, try and recover the 2732e8d8bef9SDimitry Andric // underlying value and use that instead. 2733e8d8bef9SDimitry Andric SVal recovered = 2734e8d8bef9SDimitry Andric RecoverCastedSymbol(State, Condition, N->getLocationContext(), 2735e8d8bef9SDimitry Andric N->getState()->getStateManager().getContext()); 2736e8d8bef9SDimitry Andric 2737e8d8bef9SDimitry Andric if (!recovered.isUnknown()) { 2738e8d8bef9SDimitry Andric X = recovered; 2739e8d8bef9SDimitry Andric } 2740e8d8bef9SDimitry Andric } 2741e8d8bef9SDimitry Andric } 2742e8d8bef9SDimitry Andric } 2743e8d8bef9SDimitry Andric 2744e8d8bef9SDimitry Andric // If the condition is still unknown, give up. 2745e8d8bef9SDimitry Andric if (X.isUnknownOrUndef()) 2746bdd1243dSDimitry Andric return std::nullopt; 2747e8d8bef9SDimitry Andric 2748e8d8bef9SDimitry Andric DefinedSVal V = X.castAs<DefinedSVal>(); 2749e8d8bef9SDimitry Andric 2750e8d8bef9SDimitry Andric ProgramStateRef StTrue, StFalse; 2751e8d8bef9SDimitry Andric return State->assume(V); 2752e8d8bef9SDimitry Andric } 2753e8d8bef9SDimitry Andric 27540b57cec5SDimitry Andric void ExprEngine::processBranch(const Stmt *Condition, 27550b57cec5SDimitry Andric NodeBuilderContext& BldCtx, 27560b57cec5SDimitry Andric ExplodedNode *Pred, 27570b57cec5SDimitry Andric ExplodedNodeSet &Dst, 27580b57cec5SDimitry Andric const CFGBlock *DstT, 27590b57cec5SDimitry Andric const CFGBlock *DstF) { 27600b57cec5SDimitry Andric assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) && 27610b57cec5SDimitry Andric "CXXBindTemporaryExprs are handled by processBindTemporary."); 27620b57cec5SDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 27630b57cec5SDimitry Andric PrettyStackTraceLocationContext StackCrashInfo(LCtx); 27640b57cec5SDimitry Andric currBldrCtx = &BldCtx; 27650b57cec5SDimitry Andric 27660b57cec5SDimitry Andric // Check for NULL conditions; e.g. "for(;;)" 27670b57cec5SDimitry Andric if (!Condition) { 27680b57cec5SDimitry Andric BranchNodeBuilder NullCondBldr(Pred, Dst, BldCtx, DstT, DstF); 27690b57cec5SDimitry Andric NullCondBldr.markInfeasible(false); 27700b57cec5SDimitry Andric NullCondBldr.generateNode(Pred->getState(), true, Pred); 27710b57cec5SDimitry Andric return; 27720b57cec5SDimitry Andric } 27730b57cec5SDimitry Andric 27740b57cec5SDimitry Andric if (const auto *Ex = dyn_cast<Expr>(Condition)) 27750b57cec5SDimitry Andric Condition = Ex->IgnoreParens(); 27760b57cec5SDimitry Andric 27770b57cec5SDimitry Andric Condition = ResolveCondition(Condition, BldCtx.getBlock()); 27780b57cec5SDimitry Andric PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), 27790b57cec5SDimitry Andric Condition->getBeginLoc(), 27800b57cec5SDimitry Andric "Error evaluating branch"); 27810b57cec5SDimitry Andric 27820b57cec5SDimitry Andric ExplodedNodeSet CheckersOutSet; 27830b57cec5SDimitry Andric getCheckerManager().runCheckersForBranchCondition(Condition, CheckersOutSet, 27840b57cec5SDimitry Andric Pred, *this); 27850b57cec5SDimitry Andric // We generated only sinks. 27860b57cec5SDimitry Andric if (CheckersOutSet.empty()) 27870b57cec5SDimitry Andric return; 27880b57cec5SDimitry Andric 27890b57cec5SDimitry Andric BranchNodeBuilder builder(CheckersOutSet, Dst, BldCtx, DstT, DstF); 2790e8d8bef9SDimitry Andric for (ExplodedNode *PredN : CheckersOutSet) { 2791e8d8bef9SDimitry Andric if (PredN->isSink()) 27920b57cec5SDimitry Andric continue; 27930b57cec5SDimitry Andric 2794e8d8bef9SDimitry Andric ProgramStateRef PrevState = PredN->getState(); 27950b57cec5SDimitry Andric 27960b57cec5SDimitry Andric ProgramStateRef StTrue, StFalse; 2797e8d8bef9SDimitry Andric if (const auto KnownCondValueAssumption = assumeCondition(Condition, PredN)) 2798e8d8bef9SDimitry Andric std::tie(StTrue, StFalse) = *KnownCondValueAssumption; 2799e8d8bef9SDimitry Andric else { 2800e8d8bef9SDimitry Andric assert(!isa<ObjCForCollectionStmt>(Condition)); 2801e8d8bef9SDimitry Andric builder.generateNode(PrevState, true, PredN); 2802e8d8bef9SDimitry Andric builder.generateNode(PrevState, false, PredN); 2803e8d8bef9SDimitry Andric continue; 2804e8d8bef9SDimitry Andric } 2805e8d8bef9SDimitry Andric if (StTrue && StFalse) 2806349cc55cSDimitry Andric assert(!isa<ObjCForCollectionStmt>(Condition)); 28070b57cec5SDimitry Andric 28080b57cec5SDimitry Andric // Process the true branch. 28090b57cec5SDimitry Andric if (builder.isFeasible(true)) { 28100b57cec5SDimitry Andric if (StTrue) 2811e8d8bef9SDimitry Andric builder.generateNode(StTrue, true, PredN); 28120b57cec5SDimitry Andric else 28130b57cec5SDimitry Andric builder.markInfeasible(true); 28140b57cec5SDimitry Andric } 28150b57cec5SDimitry Andric 28160b57cec5SDimitry Andric // Process the false branch. 28170b57cec5SDimitry Andric if (builder.isFeasible(false)) { 28180b57cec5SDimitry Andric if (StFalse) 2819e8d8bef9SDimitry Andric builder.generateNode(StFalse, false, PredN); 28200b57cec5SDimitry Andric else 28210b57cec5SDimitry Andric builder.markInfeasible(false); 28220b57cec5SDimitry Andric } 28230b57cec5SDimitry Andric } 28240b57cec5SDimitry Andric currBldrCtx = nullptr; 28250b57cec5SDimitry Andric } 28260b57cec5SDimitry Andric 28270b57cec5SDimitry Andric /// The GDM component containing the set of global variables which have been 28280b57cec5SDimitry Andric /// previously initialized with explicit initializers. 28290b57cec5SDimitry Andric REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet, 28300b57cec5SDimitry Andric llvm::ImmutableSet<const VarDecl *>) 28310b57cec5SDimitry Andric 28320b57cec5SDimitry Andric void ExprEngine::processStaticInitializer(const DeclStmt *DS, 28330b57cec5SDimitry Andric NodeBuilderContext &BuilderCtx, 28340b57cec5SDimitry Andric ExplodedNode *Pred, 28350b57cec5SDimitry Andric ExplodedNodeSet &Dst, 28360b57cec5SDimitry Andric const CFGBlock *DstT, 28370b57cec5SDimitry Andric const CFGBlock *DstF) { 28380b57cec5SDimitry Andric PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); 28390b57cec5SDimitry Andric currBldrCtx = &BuilderCtx; 28400b57cec5SDimitry Andric 28410b57cec5SDimitry Andric const auto *VD = cast<VarDecl>(DS->getSingleDecl()); 28420b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 28430b57cec5SDimitry Andric bool initHasRun = state->contains<InitializedGlobalsSet>(VD); 28440b57cec5SDimitry Andric BranchNodeBuilder builder(Pred, Dst, BuilderCtx, DstT, DstF); 28450b57cec5SDimitry Andric 28460b57cec5SDimitry Andric if (!initHasRun) { 28470b57cec5SDimitry Andric state = state->add<InitializedGlobalsSet>(VD); 28480b57cec5SDimitry Andric } 28490b57cec5SDimitry Andric 28500b57cec5SDimitry Andric builder.generateNode(state, initHasRun, Pred); 28510b57cec5SDimitry Andric builder.markInfeasible(!initHasRun); 28520b57cec5SDimitry Andric 28530b57cec5SDimitry Andric currBldrCtx = nullptr; 28540b57cec5SDimitry Andric } 28550b57cec5SDimitry Andric 28560b57cec5SDimitry Andric /// processIndirectGoto - Called by CoreEngine. Used to generate successor 28570b57cec5SDimitry Andric /// nodes by processing the 'effects' of a computed goto jump. 28580b57cec5SDimitry Andric void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { 28590b57cec5SDimitry Andric ProgramStateRef state = builder.getState(); 28600b57cec5SDimitry Andric SVal V = state->getSVal(builder.getTarget(), builder.getLocationContext()); 28610b57cec5SDimitry Andric 28620b57cec5SDimitry Andric // Three possibilities: 28630b57cec5SDimitry Andric // 28640b57cec5SDimitry Andric // (1) We know the computed label. 28650b57cec5SDimitry Andric // (2) The label is NULL (or some other constant), or Undefined. 28660b57cec5SDimitry Andric // (3) We have no clue about the label. Dispatch to all targets. 28670b57cec5SDimitry Andric // 28680b57cec5SDimitry Andric 28690b57cec5SDimitry Andric using iterator = IndirectGotoNodeBuilder::iterator; 28700b57cec5SDimitry Andric 2871bdd1243dSDimitry Andric if (std::optional<loc::GotoLabel> LV = V.getAs<loc::GotoLabel>()) { 28720b57cec5SDimitry Andric const LabelDecl *L = LV->getLabel(); 28730b57cec5SDimitry Andric 287406c3fb27SDimitry Andric for (iterator Succ : builder) { 287506c3fb27SDimitry Andric if (Succ.getLabel() == L) { 287606c3fb27SDimitry Andric builder.generateNode(Succ, state); 28770b57cec5SDimitry Andric return; 28780b57cec5SDimitry Andric } 28790b57cec5SDimitry Andric } 28800b57cec5SDimitry Andric 28810b57cec5SDimitry Andric llvm_unreachable("No block with label."); 28820b57cec5SDimitry Andric } 28830b57cec5SDimitry Andric 288481ad6265SDimitry Andric if (isa<UndefinedVal, loc::ConcreteInt>(V)) { 28850b57cec5SDimitry Andric // Dispatch to the first target and mark it as a sink. 28860b57cec5SDimitry Andric //ExplodedNode* N = builder.generateNode(builder.begin(), state, true); 28870b57cec5SDimitry Andric // FIXME: add checker visit. 28880b57cec5SDimitry Andric // UndefBranches.insert(N); 28890b57cec5SDimitry Andric return; 28900b57cec5SDimitry Andric } 28910b57cec5SDimitry Andric 28920b57cec5SDimitry Andric // This is really a catch-all. We don't support symbolics yet. 28930b57cec5SDimitry Andric // FIXME: Implement dispatch for symbolic pointers. 28940b57cec5SDimitry Andric 289506c3fb27SDimitry Andric for (iterator Succ : builder) 289606c3fb27SDimitry Andric builder.generateNode(Succ, state); 28970b57cec5SDimitry Andric } 28980b57cec5SDimitry Andric 28990b57cec5SDimitry Andric void ExprEngine::processBeginOfFunction(NodeBuilderContext &BC, 29000b57cec5SDimitry Andric ExplodedNode *Pred, 29010b57cec5SDimitry Andric ExplodedNodeSet &Dst, 29020b57cec5SDimitry Andric const BlockEdge &L) { 29030b57cec5SDimitry Andric SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC); 29040b57cec5SDimitry Andric getCheckerManager().runCheckersForBeginFunction(Dst, L, Pred, *this); 29050b57cec5SDimitry Andric } 29060b57cec5SDimitry Andric 29070b57cec5SDimitry Andric /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path 29080b57cec5SDimitry Andric /// nodes when the control reaches the end of a function. 29090b57cec5SDimitry Andric void ExprEngine::processEndOfFunction(NodeBuilderContext& BC, 29100b57cec5SDimitry Andric ExplodedNode *Pred, 29110b57cec5SDimitry Andric const ReturnStmt *RS) { 29120b57cec5SDimitry Andric ProgramStateRef State = Pred->getState(); 29130b57cec5SDimitry Andric 29140b57cec5SDimitry Andric if (!Pred->getStackFrame()->inTopFrame()) 29150b57cec5SDimitry Andric State = finishArgumentConstruction( 29160b57cec5SDimitry Andric State, *getStateManager().getCallEventManager().getCaller( 29170b57cec5SDimitry Andric Pred->getStackFrame(), Pred->getState())); 29180b57cec5SDimitry Andric 29190b57cec5SDimitry Andric // FIXME: We currently cannot assert that temporaries are clear, because 29200b57cec5SDimitry Andric // lifetime extended temporaries are not always modelled correctly. In some 29210b57cec5SDimitry Andric // cases when we materialize the temporary, we do 29220b57cec5SDimitry Andric // createTemporaryRegionIfNeeded(), and the region changes, and also the 29230b57cec5SDimitry Andric // respective destructor becomes automatic from temporary. So for now clean up 29240b57cec5SDimitry Andric // the state manually before asserting. Ideally, this braced block of code 29250b57cec5SDimitry Andric // should go away. 29260b57cec5SDimitry Andric { 29270b57cec5SDimitry Andric const LocationContext *FromLC = Pred->getLocationContext(); 29280b57cec5SDimitry Andric const LocationContext *ToLC = FromLC->getStackFrame()->getParent(); 29290b57cec5SDimitry Andric const LocationContext *LC = FromLC; 29300b57cec5SDimitry Andric while (LC != ToLC) { 29310b57cec5SDimitry Andric assert(LC && "ToLC must be a parent of FromLC!"); 29320b57cec5SDimitry Andric for (auto I : State->get<ObjectsUnderConstruction>()) 29330b57cec5SDimitry Andric if (I.first.getLocationContext() == LC) { 29340b57cec5SDimitry Andric // The comment above only pardons us for not cleaning up a 29350b57cec5SDimitry Andric // temporary destructor. If any other statements are found here, 29360b57cec5SDimitry Andric // it must be a separate problem. 29370b57cec5SDimitry Andric assert(I.first.getItem().getKind() == 29380b57cec5SDimitry Andric ConstructionContextItem::TemporaryDestructorKind || 29390b57cec5SDimitry Andric I.first.getItem().getKind() == 29400b57cec5SDimitry Andric ConstructionContextItem::ElidedDestructorKind); 29410b57cec5SDimitry Andric State = State->remove<ObjectsUnderConstruction>(I.first); 29420b57cec5SDimitry Andric } 29430b57cec5SDimitry Andric LC = LC->getParent(); 29440b57cec5SDimitry Andric } 29450b57cec5SDimitry Andric } 29460b57cec5SDimitry Andric 29470b57cec5SDimitry Andric // Perform the transition with cleanups. 29480b57cec5SDimitry Andric if (State != Pred->getState()) { 29490b57cec5SDimitry Andric ExplodedNodeSet PostCleanup; 29500b57cec5SDimitry Andric NodeBuilder Bldr(Pred, PostCleanup, BC); 29510b57cec5SDimitry Andric Pred = Bldr.generateNode(Pred->getLocation(), State, Pred); 29520b57cec5SDimitry Andric if (!Pred) { 29530b57cec5SDimitry Andric // The node with clean temporaries already exists. We might have reached 29540b57cec5SDimitry Andric // it on a path on which we initialize different temporaries. 29550b57cec5SDimitry Andric return; 29560b57cec5SDimitry Andric } 29570b57cec5SDimitry Andric } 29580b57cec5SDimitry Andric 29590b57cec5SDimitry Andric assert(areAllObjectsFullyConstructed(Pred->getState(), 29600b57cec5SDimitry Andric Pred->getLocationContext(), 29610b57cec5SDimitry Andric Pred->getStackFrame()->getParent())); 29620b57cec5SDimitry Andric 29630b57cec5SDimitry Andric PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); 29640b57cec5SDimitry Andric 29650b57cec5SDimitry Andric ExplodedNodeSet Dst; 29660b57cec5SDimitry Andric if (Pred->getLocationContext()->inTopFrame()) { 29670b57cec5SDimitry Andric // Remove dead symbols. 29680b57cec5SDimitry Andric ExplodedNodeSet AfterRemovedDead; 29690b57cec5SDimitry Andric removeDeadOnEndOfFunction(BC, Pred, AfterRemovedDead); 29700b57cec5SDimitry Andric 29710b57cec5SDimitry Andric // Notify checkers. 29720b57cec5SDimitry Andric for (const auto I : AfterRemovedDead) 29730b57cec5SDimitry Andric getCheckerManager().runCheckersForEndFunction(BC, Dst, I, *this, RS); 29740b57cec5SDimitry Andric } else { 29750b57cec5SDimitry Andric getCheckerManager().runCheckersForEndFunction(BC, Dst, Pred, *this, RS); 29760b57cec5SDimitry Andric } 29770b57cec5SDimitry Andric 29780b57cec5SDimitry Andric Engine.enqueueEndOfFunction(Dst, RS); 29790b57cec5SDimitry Andric } 29800b57cec5SDimitry Andric 29810b57cec5SDimitry Andric /// ProcessSwitch - Called by CoreEngine. Used to generate successor 29820b57cec5SDimitry Andric /// nodes by processing the 'effects' of a switch statement. 29830b57cec5SDimitry Andric void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { 29840b57cec5SDimitry Andric using iterator = SwitchNodeBuilder::iterator; 29850b57cec5SDimitry Andric 29860b57cec5SDimitry Andric ProgramStateRef state = builder.getState(); 29870b57cec5SDimitry Andric const Expr *CondE = builder.getCondition(); 29880b57cec5SDimitry Andric SVal CondV_untested = state->getSVal(CondE, builder.getLocationContext()); 29890b57cec5SDimitry Andric 29900b57cec5SDimitry Andric if (CondV_untested.isUndef()) { 29910b57cec5SDimitry Andric //ExplodedNode* N = builder.generateDefaultCaseNode(state, true); 29920b57cec5SDimitry Andric // FIXME: add checker 29930b57cec5SDimitry Andric //UndefBranches.insert(N); 29940b57cec5SDimitry Andric 29950b57cec5SDimitry Andric return; 29960b57cec5SDimitry Andric } 29970b57cec5SDimitry Andric DefinedOrUnknownSVal CondV = CondV_untested.castAs<DefinedOrUnknownSVal>(); 29980b57cec5SDimitry Andric 29990b57cec5SDimitry Andric ProgramStateRef DefaultSt = state; 30000b57cec5SDimitry Andric 30010b57cec5SDimitry Andric iterator I = builder.begin(), EI = builder.end(); 30020b57cec5SDimitry Andric bool defaultIsFeasible = I == EI; 30030b57cec5SDimitry Andric 30040b57cec5SDimitry Andric for ( ; I != EI; ++I) { 30050b57cec5SDimitry Andric // Successor may be pruned out during CFG construction. 30060b57cec5SDimitry Andric if (!I.getBlock()) 30070b57cec5SDimitry Andric continue; 30080b57cec5SDimitry Andric 30090b57cec5SDimitry Andric const CaseStmt *Case = I.getCase(); 30100b57cec5SDimitry Andric 30110b57cec5SDimitry Andric // Evaluate the LHS of the case value. 30120b57cec5SDimitry Andric llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext()); 30130b57cec5SDimitry Andric assert(V1.getBitWidth() == getContext().getIntWidth(CondE->getType())); 30140b57cec5SDimitry Andric 30150b57cec5SDimitry Andric // Get the RHS of the case, if it exists. 30160b57cec5SDimitry Andric llvm::APSInt V2; 30170b57cec5SDimitry Andric if (const Expr *E = Case->getRHS()) 30180b57cec5SDimitry Andric V2 = E->EvaluateKnownConstInt(getContext()); 30190b57cec5SDimitry Andric else 30200b57cec5SDimitry Andric V2 = V1; 30210b57cec5SDimitry Andric 30220b57cec5SDimitry Andric ProgramStateRef StateCase; 3023bdd1243dSDimitry Andric if (std::optional<NonLoc> NL = CondV.getAs<NonLoc>()) 30240b57cec5SDimitry Andric std::tie(StateCase, DefaultSt) = 30250b57cec5SDimitry Andric DefaultSt->assumeInclusiveRange(*NL, V1, V2); 30260b57cec5SDimitry Andric else // UnknownVal 30270b57cec5SDimitry Andric StateCase = DefaultSt; 30280b57cec5SDimitry Andric 30290b57cec5SDimitry Andric if (StateCase) 30300b57cec5SDimitry Andric builder.generateCaseStmtNode(I, StateCase); 30310b57cec5SDimitry Andric 30320b57cec5SDimitry Andric // Now "assume" that the case doesn't match. Add this state 30330b57cec5SDimitry Andric // to the default state (if it is feasible). 30340b57cec5SDimitry Andric if (DefaultSt) 30350b57cec5SDimitry Andric defaultIsFeasible = true; 30360b57cec5SDimitry Andric else { 30370b57cec5SDimitry Andric defaultIsFeasible = false; 30380b57cec5SDimitry Andric break; 30390b57cec5SDimitry Andric } 30400b57cec5SDimitry Andric } 30410b57cec5SDimitry Andric 30420b57cec5SDimitry Andric if (!defaultIsFeasible) 30430b57cec5SDimitry Andric return; 30440b57cec5SDimitry Andric 30450b57cec5SDimitry Andric // If we have switch(enum value), the default branch is not 30460b57cec5SDimitry Andric // feasible if all of the enum constants not covered by 'case:' statements 30470b57cec5SDimitry Andric // are not feasible values for the switch condition. 30480b57cec5SDimitry Andric // 30490b57cec5SDimitry Andric // Note that this isn't as accurate as it could be. Even if there isn't 30500b57cec5SDimitry Andric // a case for a particular enum value as long as that enum value isn't 30510b57cec5SDimitry Andric // feasible then it shouldn't be considered for making 'default:' reachable. 30520b57cec5SDimitry Andric const SwitchStmt *SS = builder.getSwitch(); 30530b57cec5SDimitry Andric const Expr *CondExpr = SS->getCond()->IgnoreParenImpCasts(); 30540b57cec5SDimitry Andric if (CondExpr->getType()->getAs<EnumType>()) { 30550b57cec5SDimitry Andric if (SS->isAllEnumCasesCovered()) 30560b57cec5SDimitry Andric return; 30570b57cec5SDimitry Andric } 30580b57cec5SDimitry Andric 30590b57cec5SDimitry Andric builder.generateDefaultCaseNode(DefaultSt); 30600b57cec5SDimitry Andric } 30610b57cec5SDimitry Andric 30620b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 30630b57cec5SDimitry Andric // Transfer functions: Loads and stores. 30640b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 30650b57cec5SDimitry Andric 30660b57cec5SDimitry Andric void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, 30670b57cec5SDimitry Andric ExplodedNode *Pred, 30680b57cec5SDimitry Andric ExplodedNodeSet &Dst) { 30690b57cec5SDimitry Andric StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); 30700b57cec5SDimitry Andric 30710b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 30720b57cec5SDimitry Andric const LocationContext *LCtx = Pred->getLocationContext(); 30730b57cec5SDimitry Andric 30740b57cec5SDimitry Andric if (const auto *VD = dyn_cast<VarDecl>(D)) { 30750b57cec5SDimitry Andric // C permits "extern void v", and if you cast the address to a valid type, 30760b57cec5SDimitry Andric // you can even do things with it. We simply pretend 30770b57cec5SDimitry Andric assert(Ex->isGLValue() || VD->getType()->isVoidType()); 30780b57cec5SDimitry Andric const LocationContext *LocCtxt = Pred->getLocationContext(); 30790b57cec5SDimitry Andric const Decl *D = LocCtxt->getDecl(); 30800b57cec5SDimitry Andric const auto *MD = dyn_cast_or_null<CXXMethodDecl>(D); 30810b57cec5SDimitry Andric const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex); 3082bdd1243dSDimitry Andric std::optional<std::pair<SVal, QualType>> VInfo; 30830b57cec5SDimitry Andric 30840b57cec5SDimitry Andric if (AMgr.options.ShouldInlineLambdas && DeclRefEx && 30850b57cec5SDimitry Andric DeclRefEx->refersToEnclosingVariableOrCapture() && MD && 30860b57cec5SDimitry Andric MD->getParent()->isLambda()) { 30870b57cec5SDimitry Andric // Lookup the field of the lambda. 30880b57cec5SDimitry Andric const CXXRecordDecl *CXXRec = MD->getParent(); 3089bdd1243dSDimitry Andric llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields; 30900b57cec5SDimitry Andric FieldDecl *LambdaThisCaptureField; 30910b57cec5SDimitry Andric CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField); 30920b57cec5SDimitry Andric 30930b57cec5SDimitry Andric // Sema follows a sequence of complex rules to determine whether the 30940b57cec5SDimitry Andric // variable should be captured. 30950b57cec5SDimitry Andric if (const FieldDecl *FD = LambdaCaptureFields[VD]) { 30960b57cec5SDimitry Andric Loc CXXThis = 30970b57cec5SDimitry Andric svalBuilder.getCXXThis(MD, LocCtxt->getStackFrame()); 30980b57cec5SDimitry Andric SVal CXXThisVal = state->getSVal(CXXThis); 30990b57cec5SDimitry Andric VInfo = std::make_pair(state->getLValue(FD, CXXThisVal), FD->getType()); 31000b57cec5SDimitry Andric } 31010b57cec5SDimitry Andric } 31020b57cec5SDimitry Andric 31030b57cec5SDimitry Andric if (!VInfo) 31040b57cec5SDimitry Andric VInfo = std::make_pair(state->getLValue(VD, LocCtxt), VD->getType()); 31050b57cec5SDimitry Andric 31060b57cec5SDimitry Andric SVal V = VInfo->first; 31070b57cec5SDimitry Andric bool IsReference = VInfo->second->isReferenceType(); 31080b57cec5SDimitry Andric 31090b57cec5SDimitry Andric // For references, the 'lvalue' is the pointer address stored in the 31100b57cec5SDimitry Andric // reference region. 31110b57cec5SDimitry Andric if (IsReference) { 31120b57cec5SDimitry Andric if (const MemRegion *R = V.getAsRegion()) 31130b57cec5SDimitry Andric V = state->getSVal(R); 31140b57cec5SDimitry Andric else 31150b57cec5SDimitry Andric V = UnknownVal(); 31160b57cec5SDimitry Andric } 31170b57cec5SDimitry Andric 31180b57cec5SDimitry Andric Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, 31190b57cec5SDimitry Andric ProgramPoint::PostLValueKind); 31200b57cec5SDimitry Andric return; 31210b57cec5SDimitry Andric } 31220b57cec5SDimitry Andric if (const auto *ED = dyn_cast<EnumConstantDecl>(D)) { 31230b57cec5SDimitry Andric assert(!Ex->isGLValue()); 31240b57cec5SDimitry Andric SVal V = svalBuilder.makeIntVal(ED->getInitVal()); 31250b57cec5SDimitry Andric Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V)); 31260b57cec5SDimitry Andric return; 31270b57cec5SDimitry Andric } 31280b57cec5SDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 31290b57cec5SDimitry Andric SVal V = svalBuilder.getFunctionPointer(FD); 31300b57cec5SDimitry Andric Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, 31310b57cec5SDimitry Andric ProgramPoint::PostLValueKind); 31320b57cec5SDimitry Andric return; 31330b57cec5SDimitry Andric } 3134349cc55cSDimitry Andric if (isa<FieldDecl, IndirectFieldDecl>(D)) { 3135e8d8bef9SDimitry Andric // Delegate all work related to pointer to members to the surrounding 3136e8d8bef9SDimitry Andric // operator&. 31370b57cec5SDimitry Andric return; 31380b57cec5SDimitry Andric } 313981ad6265SDimitry Andric if (const auto *BD = dyn_cast<BindingDecl>(D)) { 314081ad6265SDimitry Andric const auto *DD = cast<DecompositionDecl>(BD->getDecomposedDecl()); 314181ad6265SDimitry Andric 314281ad6265SDimitry Andric SVal Base = state->getLValue(DD, LCtx); 314381ad6265SDimitry Andric if (DD->getType()->isReferenceType()) { 3144972a253aSDimitry Andric if (const MemRegion *R = Base.getAsRegion()) 3145972a253aSDimitry Andric Base = state->getSVal(R); 3146972a253aSDimitry Andric else 3147972a253aSDimitry Andric Base = UnknownVal(); 314881ad6265SDimitry Andric } 314981ad6265SDimitry Andric 315081ad6265SDimitry Andric SVal V = UnknownVal(); 315181ad6265SDimitry Andric 315281ad6265SDimitry Andric // Handle binding to data members 315381ad6265SDimitry Andric if (const auto *ME = dyn_cast<MemberExpr>(BD->getBinding())) { 315481ad6265SDimitry Andric const auto *Field = cast<FieldDecl>(ME->getMemberDecl()); 315581ad6265SDimitry Andric V = state->getLValue(Field, Base); 315681ad6265SDimitry Andric } 315781ad6265SDimitry Andric // Handle binding to arrays 315881ad6265SDimitry Andric else if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BD->getBinding())) { 315981ad6265SDimitry Andric SVal Idx = state->getSVal(ASE->getIdx(), LCtx); 316081ad6265SDimitry Andric 316181ad6265SDimitry Andric // Note: the index of an element in a structured binding is automatically 316281ad6265SDimitry Andric // created and it is a unique identifier of the specific element. Thus it 316381ad6265SDimitry Andric // cannot be a value that varies at runtime. 316481ad6265SDimitry Andric assert(Idx.isConstant() && "BindingDecl array index is not a constant!"); 316581ad6265SDimitry Andric 316681ad6265SDimitry Andric V = state->getLValue(BD->getType(), Idx, Base); 316781ad6265SDimitry Andric } 3168972a253aSDimitry Andric // Handle binding to tuple-like structures 3169972a253aSDimitry Andric else if (const auto *HV = BD->getHoldingVar()) { 3170972a253aSDimitry Andric V = state->getLValue(HV, LCtx); 3171972a253aSDimitry Andric 3172972a253aSDimitry Andric if (HV->getType()->isReferenceType()) { 3173972a253aSDimitry Andric if (const MemRegion *R = V.getAsRegion()) 3174972a253aSDimitry Andric V = state->getSVal(R); 3175972a253aSDimitry Andric else 3176972a253aSDimitry Andric V = UnknownVal(); 3177972a253aSDimitry Andric } 317881ad6265SDimitry Andric } else 317981ad6265SDimitry Andric llvm_unreachable("An unknown case of structured binding encountered!"); 318081ad6265SDimitry Andric 3181972a253aSDimitry Andric // In case of tuple-like types the references are already handled, so we 3182972a253aSDimitry Andric // don't want to handle them again. 3183972a253aSDimitry Andric if (BD->getType()->isReferenceType() && !BD->getHoldingVar()) { 3184972a253aSDimitry Andric if (const MemRegion *R = V.getAsRegion()) 3185972a253aSDimitry Andric V = state->getSVal(R); 3186972a253aSDimitry Andric else 3187972a253aSDimitry Andric V = UnknownVal(); 3188972a253aSDimitry Andric } 318981ad6265SDimitry Andric 319081ad6265SDimitry Andric Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, 319181ad6265SDimitry Andric ProgramPoint::PostLValueKind); 319281ad6265SDimitry Andric 31930b57cec5SDimitry Andric return; 31940b57cec5SDimitry Andric } 31950b57cec5SDimitry Andric 3196f3fd488fSDimitry Andric if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(D)) { 3197f3fd488fSDimitry Andric // FIXME: We should meaningfully implement this. 3198f3fd488fSDimitry Andric (void)TPO; 3199f3fd488fSDimitry Andric return; 3200f3fd488fSDimitry Andric } 3201f3fd488fSDimitry Andric 32020b57cec5SDimitry Andric llvm_unreachable("Support for this Decl not implemented."); 32030b57cec5SDimitry Andric } 32040b57cec5SDimitry Andric 320581ad6265SDimitry Andric /// VisitArrayInitLoopExpr - Transfer function for array init loop. 320681ad6265SDimitry Andric void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex, 320781ad6265SDimitry Andric ExplodedNode *Pred, 320881ad6265SDimitry Andric ExplodedNodeSet &Dst) { 320981ad6265SDimitry Andric ExplodedNodeSet CheckerPreStmt; 321081ad6265SDimitry Andric getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, Ex, *this); 321181ad6265SDimitry Andric 321281ad6265SDimitry Andric ExplodedNodeSet EvalSet; 321381ad6265SDimitry Andric StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx); 321481ad6265SDimitry Andric 321581ad6265SDimitry Andric const Expr *Arr = Ex->getCommonExpr()->getSourceExpr(); 321681ad6265SDimitry Andric 321781ad6265SDimitry Andric for (auto *Node : CheckerPreStmt) { 3218972a253aSDimitry Andric 3219972a253aSDimitry Andric // The constructor visitior has already taken care of everything. 3220bdd1243dSDimitry Andric if (isa<CXXConstructExpr>(Ex->getSubExpr())) 3221972a253aSDimitry Andric break; 3222972a253aSDimitry Andric 322381ad6265SDimitry Andric const LocationContext *LCtx = Node->getLocationContext(); 322481ad6265SDimitry Andric ProgramStateRef state = Node->getState(); 322581ad6265SDimitry Andric 322681ad6265SDimitry Andric SVal Base = UnknownVal(); 322781ad6265SDimitry Andric 322881ad6265SDimitry Andric // As in case of this expression the sub-expressions are not visited by any 322981ad6265SDimitry Andric // other transfer functions, they are handled by matching their AST. 323081ad6265SDimitry Andric 323181ad6265SDimitry Andric // Case of implicit copy or move ctor of object with array member 323281ad6265SDimitry Andric // 323381ad6265SDimitry Andric // Note: ExprEngine::VisitMemberExpr is not able to bind the array to the 323481ad6265SDimitry Andric // environment. 323581ad6265SDimitry Andric // 323681ad6265SDimitry Andric // struct S { 323781ad6265SDimitry Andric // int arr[2]; 323881ad6265SDimitry Andric // }; 323981ad6265SDimitry Andric // 324081ad6265SDimitry Andric // 324181ad6265SDimitry Andric // S a; 324281ad6265SDimitry Andric // S b = a; 324381ad6265SDimitry Andric // 324481ad6265SDimitry Andric // The AST in case of a *copy constructor* looks like this: 324581ad6265SDimitry Andric // ArrayInitLoopExpr 324681ad6265SDimitry Andric // |-OpaqueValueExpr 324781ad6265SDimitry Andric // | `-MemberExpr <-- match this 324881ad6265SDimitry Andric // | `-DeclRefExpr 324981ad6265SDimitry Andric // ` ... 325081ad6265SDimitry Andric // 325181ad6265SDimitry Andric // 325281ad6265SDimitry Andric // S c; 325381ad6265SDimitry Andric // S d = std::move(d); 325481ad6265SDimitry Andric // 325581ad6265SDimitry Andric // In case of a *move constructor* the resulting AST looks like: 325681ad6265SDimitry Andric // ArrayInitLoopExpr 325781ad6265SDimitry Andric // |-OpaqueValueExpr 325881ad6265SDimitry Andric // | `-MemberExpr <-- match this first 325981ad6265SDimitry Andric // | `-CXXStaticCastExpr <-- match this after 326081ad6265SDimitry Andric // | `-DeclRefExpr 326181ad6265SDimitry Andric // ` ... 326281ad6265SDimitry Andric if (const auto *ME = dyn_cast<MemberExpr>(Arr)) { 326381ad6265SDimitry Andric Expr *MEBase = ME->getBase(); 326481ad6265SDimitry Andric 326581ad6265SDimitry Andric // Move ctor 326681ad6265SDimitry Andric if (auto CXXSCE = dyn_cast<CXXStaticCastExpr>(MEBase)) { 326781ad6265SDimitry Andric MEBase = CXXSCE->getSubExpr(); 326881ad6265SDimitry Andric } 326981ad6265SDimitry Andric 327081ad6265SDimitry Andric auto ObjDeclExpr = cast<DeclRefExpr>(MEBase); 327181ad6265SDimitry Andric SVal Obj = state->getLValue(cast<VarDecl>(ObjDeclExpr->getDecl()), LCtx); 327281ad6265SDimitry Andric 327381ad6265SDimitry Andric Base = state->getLValue(cast<FieldDecl>(ME->getMemberDecl()), Obj); 327481ad6265SDimitry Andric } 327581ad6265SDimitry Andric 327681ad6265SDimitry Andric // Case of lambda capture and decomposition declaration 327781ad6265SDimitry Andric // 327881ad6265SDimitry Andric // int arr[2]; 327981ad6265SDimitry Andric // 328081ad6265SDimitry Andric // [arr]{ int a = arr[0]; }(); 328181ad6265SDimitry Andric // auto[a, b] = arr; 328281ad6265SDimitry Andric // 328381ad6265SDimitry Andric // In both of these cases the AST looks like the following: 328481ad6265SDimitry Andric // ArrayInitLoopExpr 328581ad6265SDimitry Andric // |-OpaqueValueExpr 328681ad6265SDimitry Andric // | `-DeclRefExpr <-- match this 328781ad6265SDimitry Andric // ` ... 328881ad6265SDimitry Andric if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arr)) 328981ad6265SDimitry Andric Base = state->getLValue(cast<VarDecl>(DRE->getDecl()), LCtx); 329081ad6265SDimitry Andric 329181ad6265SDimitry Andric // Create a lazy compound value to the original array 329281ad6265SDimitry Andric if (const MemRegion *R = Base.getAsRegion()) 329381ad6265SDimitry Andric Base = state->getSVal(R); 329481ad6265SDimitry Andric else 329581ad6265SDimitry Andric Base = UnknownVal(); 329681ad6265SDimitry Andric 329781ad6265SDimitry Andric Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, Base)); 329881ad6265SDimitry Andric } 329981ad6265SDimitry Andric 330081ad6265SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); 330181ad6265SDimitry Andric } 330281ad6265SDimitry Andric 33030b57cec5SDimitry Andric /// VisitArraySubscriptExpr - Transfer function for array accesses 33040b57cec5SDimitry Andric void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A, 33050b57cec5SDimitry Andric ExplodedNode *Pred, 33060b57cec5SDimitry Andric ExplodedNodeSet &Dst){ 33070b57cec5SDimitry Andric const Expr *Base = A->getBase()->IgnoreParens(); 33080b57cec5SDimitry Andric const Expr *Idx = A->getIdx()->IgnoreParens(); 33090b57cec5SDimitry Andric 33100b57cec5SDimitry Andric ExplodedNodeSet CheckerPreStmt; 33110b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this); 33120b57cec5SDimitry Andric 33130b57cec5SDimitry Andric ExplodedNodeSet EvalSet; 33140b57cec5SDimitry Andric StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx); 33150b57cec5SDimitry Andric 33160b57cec5SDimitry Andric bool IsVectorType = A->getBase()->getType()->isVectorType(); 33170b57cec5SDimitry Andric 33180b57cec5SDimitry Andric // The "like" case is for situations where C standard prohibits the type to 33190b57cec5SDimitry Andric // be an lvalue, e.g. taking the address of a subscript of an expression of 33200b57cec5SDimitry Andric // type "void *". 33210b57cec5SDimitry Andric bool IsGLValueLike = A->isGLValue() || 33220b57cec5SDimitry Andric (A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus); 33230b57cec5SDimitry Andric 33240b57cec5SDimitry Andric for (auto *Node : CheckerPreStmt) { 33250b57cec5SDimitry Andric const LocationContext *LCtx = Node->getLocationContext(); 33260b57cec5SDimitry Andric ProgramStateRef state = Node->getState(); 33270b57cec5SDimitry Andric 33280b57cec5SDimitry Andric if (IsGLValueLike) { 33290b57cec5SDimitry Andric QualType T = A->getType(); 33300b57cec5SDimitry Andric 33310b57cec5SDimitry Andric // One of the forbidden LValue types! We still need to have sensible 33320b57cec5SDimitry Andric // symbolic locations to represent this stuff. Note that arithmetic on 33330b57cec5SDimitry Andric // void pointers is a GCC extension. 33340b57cec5SDimitry Andric if (T->isVoidType()) 33350b57cec5SDimitry Andric T = getContext().CharTy; 33360b57cec5SDimitry Andric 33370b57cec5SDimitry Andric SVal V = state->getLValue(T, 33380b57cec5SDimitry Andric state->getSVal(Idx, LCtx), 33390b57cec5SDimitry Andric state->getSVal(Base, LCtx)); 33400b57cec5SDimitry Andric Bldr.generateNode(A, Node, state->BindExpr(A, LCtx, V), nullptr, 33410b57cec5SDimitry Andric ProgramPoint::PostLValueKind); 33420b57cec5SDimitry Andric } else if (IsVectorType) { 33430b57cec5SDimitry Andric // FIXME: non-glvalue vector reads are not modelled. 33440b57cec5SDimitry Andric Bldr.generateNode(A, Node, state, nullptr); 33450b57cec5SDimitry Andric } else { 33460b57cec5SDimitry Andric llvm_unreachable("Array subscript should be an lValue when not \ 33470b57cec5SDimitry Andric a vector and not a forbidden lvalue type"); 33480b57cec5SDimitry Andric } 33490b57cec5SDimitry Andric } 33500b57cec5SDimitry Andric 33510b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this); 33520b57cec5SDimitry Andric } 33530b57cec5SDimitry Andric 33540b57cec5SDimitry Andric /// VisitMemberExpr - Transfer function for member expressions. 33550b57cec5SDimitry Andric void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, 33560b57cec5SDimitry Andric ExplodedNodeSet &Dst) { 33570b57cec5SDimitry Andric // FIXME: Prechecks eventually go in ::Visit(). 33580b57cec5SDimitry Andric ExplodedNodeSet CheckedSet; 33590b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this); 33600b57cec5SDimitry Andric 33610b57cec5SDimitry Andric ExplodedNodeSet EvalSet; 33620b57cec5SDimitry Andric ValueDecl *Member = M->getMemberDecl(); 33630b57cec5SDimitry Andric 33640b57cec5SDimitry Andric // Handle static member variables and enum constants accessed via 33650b57cec5SDimitry Andric // member syntax. 3366349cc55cSDimitry Andric if (isa<VarDecl, EnumConstantDecl>(Member)) { 33670b57cec5SDimitry Andric for (const auto I : CheckedSet) 33680b57cec5SDimitry Andric VisitCommonDeclRefExpr(M, Member, I, EvalSet); 33690b57cec5SDimitry Andric } else { 33700b57cec5SDimitry Andric StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); 33710b57cec5SDimitry Andric ExplodedNodeSet Tmp; 33720b57cec5SDimitry Andric 33730b57cec5SDimitry Andric for (const auto I : CheckedSet) { 33740b57cec5SDimitry Andric ProgramStateRef state = I->getState(); 33750b57cec5SDimitry Andric const LocationContext *LCtx = I->getLocationContext(); 33760b57cec5SDimitry Andric Expr *BaseExpr = M->getBase(); 33770b57cec5SDimitry Andric 33780b57cec5SDimitry Andric // Handle C++ method calls. 33790b57cec5SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(Member)) { 33805f757f3fSDimitry Andric if (MD->isImplicitObjectMemberFunction()) 33810b57cec5SDimitry Andric state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); 33820b57cec5SDimitry Andric 33830b57cec5SDimitry Andric SVal MDVal = svalBuilder.getFunctionPointer(MD); 33840b57cec5SDimitry Andric state = state->BindExpr(M, LCtx, MDVal); 33850b57cec5SDimitry Andric 33860b57cec5SDimitry Andric Bldr.generateNode(M, I, state); 33870b57cec5SDimitry Andric continue; 33880b57cec5SDimitry Andric } 33890b57cec5SDimitry Andric 33900b57cec5SDimitry Andric // Handle regular struct fields / member variables. 33910b57cec5SDimitry Andric const SubRegion *MR = nullptr; 33920b57cec5SDimitry Andric state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr, 33930b57cec5SDimitry Andric /*Result=*/nullptr, 33940b57cec5SDimitry Andric /*OutRegionWithAdjustments=*/&MR); 33950b57cec5SDimitry Andric SVal baseExprVal = 33960b57cec5SDimitry Andric MR ? loc::MemRegionVal(MR) : state->getSVal(BaseExpr, LCtx); 33970b57cec5SDimitry Andric 3398bdd1243dSDimitry Andric // FIXME: Copied from RegionStoreManager::bind() 3399bdd1243dSDimitry Andric if (const auto *SR = 3400bdd1243dSDimitry Andric dyn_cast_or_null<SymbolicRegion>(baseExprVal.getAsRegion())) { 3401bdd1243dSDimitry Andric QualType T = SR->getPointeeStaticType(); 3402bdd1243dSDimitry Andric baseExprVal = 3403bdd1243dSDimitry Andric loc::MemRegionVal(getStoreManager().GetElementZeroRegion(SR, T)); 3404bdd1243dSDimitry Andric } 3405bdd1243dSDimitry Andric 34060b57cec5SDimitry Andric const auto *field = cast<FieldDecl>(Member); 34070b57cec5SDimitry Andric SVal L = state->getLValue(field, baseExprVal); 34080b57cec5SDimitry Andric 34090b57cec5SDimitry Andric if (M->isGLValue() || M->getType()->isArrayType()) { 34100b57cec5SDimitry Andric // We special-case rvalues of array type because the analyzer cannot 34110b57cec5SDimitry Andric // reason about them, since we expect all regions to be wrapped in Locs. 34120b57cec5SDimitry Andric // We instead treat these as lvalues and assume that they will decay to 34130b57cec5SDimitry Andric // pointers as soon as they are used. 34140b57cec5SDimitry Andric if (!M->isGLValue()) { 34150b57cec5SDimitry Andric assert(M->getType()->isArrayType()); 34160b57cec5SDimitry Andric const auto *PE = 34170b57cec5SDimitry Andric dyn_cast<ImplicitCastExpr>(I->getParentMap().getParentIgnoreParens(M)); 34180b57cec5SDimitry Andric if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { 34190b57cec5SDimitry Andric llvm_unreachable("should always be wrapped in ArrayToPointerDecay"); 34200b57cec5SDimitry Andric } 34210b57cec5SDimitry Andric } 34220b57cec5SDimitry Andric 34230b57cec5SDimitry Andric if (field->getType()->isReferenceType()) { 34240b57cec5SDimitry Andric if (const MemRegion *R = L.getAsRegion()) 34250b57cec5SDimitry Andric L = state->getSVal(R); 34260b57cec5SDimitry Andric else 34270b57cec5SDimitry Andric L = UnknownVal(); 34280b57cec5SDimitry Andric } 34290b57cec5SDimitry Andric 34300b57cec5SDimitry Andric Bldr.generateNode(M, I, state->BindExpr(M, LCtx, L), nullptr, 34310b57cec5SDimitry Andric ProgramPoint::PostLValueKind); 34320b57cec5SDimitry Andric } else { 34330b57cec5SDimitry Andric Bldr.takeNodes(I); 34340b57cec5SDimitry Andric evalLoad(Tmp, M, M, I, state, L); 34350b57cec5SDimitry Andric Bldr.addNodes(Tmp); 34360b57cec5SDimitry Andric } 34370b57cec5SDimitry Andric } 34380b57cec5SDimitry Andric } 34390b57cec5SDimitry Andric 34400b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this); 34410b57cec5SDimitry Andric } 34420b57cec5SDimitry Andric 34430b57cec5SDimitry Andric void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred, 34440b57cec5SDimitry Andric ExplodedNodeSet &Dst) { 34450b57cec5SDimitry Andric ExplodedNodeSet AfterPreSet; 34460b57cec5SDimitry Andric getCheckerManager().runCheckersForPreStmt(AfterPreSet, Pred, AE, *this); 34470b57cec5SDimitry Andric 34480b57cec5SDimitry Andric // For now, treat all the arguments to C11 atomics as escaping. 34490b57cec5SDimitry Andric // FIXME: Ideally we should model the behavior of the atomics precisely here. 34500b57cec5SDimitry Andric 34510b57cec5SDimitry Andric ExplodedNodeSet AfterInvalidateSet; 34520b57cec5SDimitry Andric StmtNodeBuilder Bldr(AfterPreSet, AfterInvalidateSet, *currBldrCtx); 34530b57cec5SDimitry Andric 34540b57cec5SDimitry Andric for (const auto I : AfterPreSet) { 34550b57cec5SDimitry Andric ProgramStateRef State = I->getState(); 34560b57cec5SDimitry Andric const LocationContext *LCtx = I->getLocationContext(); 34570b57cec5SDimitry Andric 34580b57cec5SDimitry Andric SmallVector<SVal, 8> ValuesToInvalidate; 34590b57cec5SDimitry Andric for (unsigned SI = 0, Count = AE->getNumSubExprs(); SI != Count; SI++) { 34600b57cec5SDimitry Andric const Expr *SubExpr = AE->getSubExprs()[SI]; 34610b57cec5SDimitry Andric SVal SubExprVal = State->getSVal(SubExpr, LCtx); 34620b57cec5SDimitry Andric ValuesToInvalidate.push_back(SubExprVal); 34630b57cec5SDimitry Andric } 34640b57cec5SDimitry Andric 34650b57cec5SDimitry Andric State = State->invalidateRegions(ValuesToInvalidate, AE, 34660b57cec5SDimitry Andric currBldrCtx->blockCount(), 34670b57cec5SDimitry Andric LCtx, 34680b57cec5SDimitry Andric /*CausedByPointerEscape*/true, 34690b57cec5SDimitry Andric /*Symbols=*/nullptr); 34700b57cec5SDimitry Andric 34710b57cec5SDimitry Andric SVal ResultVal = UnknownVal(); 34720b57cec5SDimitry Andric State = State->BindExpr(AE, LCtx, ResultVal); 34730b57cec5SDimitry Andric Bldr.generateNode(AE, I, State, nullptr, 34740b57cec5SDimitry Andric ProgramPoint::PostStmtKind); 34750b57cec5SDimitry Andric } 34760b57cec5SDimitry Andric 34770b57cec5SDimitry Andric getCheckerManager().runCheckersForPostStmt(Dst, AfterInvalidateSet, AE, *this); 34780b57cec5SDimitry Andric } 34790b57cec5SDimitry Andric 34800b57cec5SDimitry Andric // A value escapes in four possible cases: 34810b57cec5SDimitry Andric // (1) We are binding to something that is not a memory region. 34820b57cec5SDimitry Andric // (2) We are binding to a MemRegion that does not have stack storage. 34830b57cec5SDimitry Andric // (3) We are binding to a top-level parameter region with a non-trivial 34840b57cec5SDimitry Andric // destructor. We won't see the destructor during analysis, but it's there. 34850b57cec5SDimitry Andric // (4) We are binding to a MemRegion with stack storage that the store 34860b57cec5SDimitry Andric // does not understand. 3487480093f4SDimitry Andric ProgramStateRef ExprEngine::processPointerEscapedOnBind( 3488480093f4SDimitry Andric ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals, 3489480093f4SDimitry Andric const LocationContext *LCtx, PointerEscapeKind Kind, 3490480093f4SDimitry Andric const CallEvent *Call) { 3491480093f4SDimitry Andric SmallVector<SVal, 8> Escaped; 3492480093f4SDimitry Andric for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) { 34930b57cec5SDimitry Andric // Cases (1) and (2). 3494480093f4SDimitry Andric const MemRegion *MR = LocAndVal.first.getAsRegion(); 3495bdd1243dSDimitry Andric if (!MR || 3496bdd1243dSDimitry Andric !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MR->getMemorySpace())) { 3497480093f4SDimitry Andric Escaped.push_back(LocAndVal.second); 3498480093f4SDimitry Andric continue; 3499480093f4SDimitry Andric } 35000b57cec5SDimitry Andric 35010b57cec5SDimitry Andric // Case (3). 35020b57cec5SDimitry Andric if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion())) 35030b57cec5SDimitry Andric if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame()) 35040b57cec5SDimitry Andric if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl()) 3505480093f4SDimitry Andric if (!RD->hasTrivialDestructor()) { 3506480093f4SDimitry Andric Escaped.push_back(LocAndVal.second); 3507480093f4SDimitry Andric continue; 3508480093f4SDimitry Andric } 35090b57cec5SDimitry Andric 35100b57cec5SDimitry Andric // Case (4): in order to test that, generate a new state with the binding 35110b57cec5SDimitry Andric // added. If it is the same state, then it escapes (since the store cannot 35120b57cec5SDimitry Andric // represent the binding). 35130b57cec5SDimitry Andric // Do this only if we know that the store is not supposed to generate the 35140b57cec5SDimitry Andric // same state. 35150b57cec5SDimitry Andric SVal StoredVal = State->getSVal(MR); 3516480093f4SDimitry Andric if (StoredVal != LocAndVal.second) 3517480093f4SDimitry Andric if (State == 3518480093f4SDimitry Andric (State->bindLoc(loc::MemRegionVal(MR), LocAndVal.second, LCtx))) 3519480093f4SDimitry Andric Escaped.push_back(LocAndVal.second); 3520480093f4SDimitry Andric } 35210b57cec5SDimitry Andric 3522480093f4SDimitry Andric if (Escaped.empty()) 35230b57cec5SDimitry Andric return State; 3524480093f4SDimitry Andric 3525480093f4SDimitry Andric return escapeValues(State, Escaped, Kind, Call); 3526480093f4SDimitry Andric } 3527480093f4SDimitry Andric 3528480093f4SDimitry Andric ProgramStateRef 3529480093f4SDimitry Andric ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, 3530480093f4SDimitry Andric SVal Val, const LocationContext *LCtx) { 3531480093f4SDimitry Andric std::pair<SVal, SVal> LocAndVal(Loc, Val); 3532480093f4SDimitry Andric return processPointerEscapedOnBind(State, LocAndVal, LCtx, PSK_EscapeOnBind, 3533480093f4SDimitry Andric nullptr); 35340b57cec5SDimitry Andric } 35350b57cec5SDimitry Andric 35360b57cec5SDimitry Andric ProgramStateRef 35370b57cec5SDimitry Andric ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State, 35380b57cec5SDimitry Andric const InvalidatedSymbols *Invalidated, 35390b57cec5SDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 35400b57cec5SDimitry Andric const CallEvent *Call, 35410b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits &ITraits) { 35420b57cec5SDimitry Andric if (!Invalidated || Invalidated->empty()) 35430b57cec5SDimitry Andric return State; 35440b57cec5SDimitry Andric 35450b57cec5SDimitry Andric if (!Call) 35460b57cec5SDimitry Andric return getCheckerManager().runCheckersForPointerEscape(State, 35470b57cec5SDimitry Andric *Invalidated, 35480b57cec5SDimitry Andric nullptr, 35490b57cec5SDimitry Andric PSK_EscapeOther, 35500b57cec5SDimitry Andric &ITraits); 35510b57cec5SDimitry Andric 35520b57cec5SDimitry Andric // If the symbols were invalidated by a call, we want to find out which ones 35530b57cec5SDimitry Andric // were invalidated directly due to being arguments to the call. 35540b57cec5SDimitry Andric InvalidatedSymbols SymbolsDirectlyInvalidated; 35550b57cec5SDimitry Andric for (const auto I : ExplicitRegions) { 35560b57cec5SDimitry Andric if (const SymbolicRegion *R = I->StripCasts()->getAs<SymbolicRegion>()) 35570b57cec5SDimitry Andric SymbolsDirectlyInvalidated.insert(R->getSymbol()); 35580b57cec5SDimitry Andric } 35590b57cec5SDimitry Andric 35600b57cec5SDimitry Andric InvalidatedSymbols SymbolsIndirectlyInvalidated; 35610b57cec5SDimitry Andric for (const auto &sym : *Invalidated) { 35620b57cec5SDimitry Andric if (SymbolsDirectlyInvalidated.count(sym)) 35630b57cec5SDimitry Andric continue; 35640b57cec5SDimitry Andric SymbolsIndirectlyInvalidated.insert(sym); 35650b57cec5SDimitry Andric } 35660b57cec5SDimitry Andric 35670b57cec5SDimitry Andric if (!SymbolsDirectlyInvalidated.empty()) 35680b57cec5SDimitry Andric State = getCheckerManager().runCheckersForPointerEscape(State, 35690b57cec5SDimitry Andric SymbolsDirectlyInvalidated, Call, PSK_DirectEscapeOnCall, &ITraits); 35700b57cec5SDimitry Andric 35710b57cec5SDimitry Andric // Notify about the symbols that get indirectly invalidated by the call. 35720b57cec5SDimitry Andric if (!SymbolsIndirectlyInvalidated.empty()) 35730b57cec5SDimitry Andric State = getCheckerManager().runCheckersForPointerEscape(State, 35740b57cec5SDimitry Andric SymbolsIndirectlyInvalidated, Call, PSK_IndirectEscapeOnCall, &ITraits); 35750b57cec5SDimitry Andric 35760b57cec5SDimitry Andric return State; 35770b57cec5SDimitry Andric } 35780b57cec5SDimitry Andric 35790b57cec5SDimitry Andric /// evalBind - Handle the semantics of binding a value to a specific location. 35800b57cec5SDimitry Andric /// This method is used by evalStore and (soon) VisitDeclStmt, and others. 35810b57cec5SDimitry Andric void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, 35820b57cec5SDimitry Andric ExplodedNode *Pred, 35830b57cec5SDimitry Andric SVal location, SVal Val, 35840b57cec5SDimitry Andric bool atDeclInit, const ProgramPoint *PP) { 35850b57cec5SDimitry Andric const LocationContext *LC = Pred->getLocationContext(); 35860b57cec5SDimitry Andric PostStmt PS(StoreE, LC); 35870b57cec5SDimitry Andric if (!PP) 35880b57cec5SDimitry Andric PP = &PS; 35890b57cec5SDimitry Andric 35900b57cec5SDimitry Andric // Do a previsit of the bind. 35910b57cec5SDimitry Andric ExplodedNodeSet CheckedSet; 35920b57cec5SDimitry Andric getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val, 35930b57cec5SDimitry Andric StoreE, *this, *PP); 35940b57cec5SDimitry Andric 35950b57cec5SDimitry Andric StmtNodeBuilder Bldr(CheckedSet, Dst, *currBldrCtx); 35960b57cec5SDimitry Andric 35970b57cec5SDimitry Andric // If the location is not a 'Loc', it will already be handled by 35980b57cec5SDimitry Andric // the checkers. There is nothing left to do. 359981ad6265SDimitry Andric if (!isa<Loc>(location)) { 36000b57cec5SDimitry Andric const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/nullptr, 36010b57cec5SDimitry Andric /*tag*/nullptr); 36020b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 36030b57cec5SDimitry Andric state = processPointerEscapedOnBind(state, location, Val, LC); 36040b57cec5SDimitry Andric Bldr.generateNode(L, state, Pred); 36050b57cec5SDimitry Andric return; 36060b57cec5SDimitry Andric } 36070b57cec5SDimitry Andric 36080b57cec5SDimitry Andric for (const auto PredI : CheckedSet) { 36090b57cec5SDimitry Andric ProgramStateRef state = PredI->getState(); 36100b57cec5SDimitry Andric 36110b57cec5SDimitry Andric state = processPointerEscapedOnBind(state, location, Val, LC); 36120b57cec5SDimitry Andric 36130b57cec5SDimitry Andric // When binding the value, pass on the hint that this is a initialization. 36140b57cec5SDimitry Andric // For initializations, we do not need to inform clients of region 36150b57cec5SDimitry Andric // changes. 36160b57cec5SDimitry Andric state = state->bindLoc(location.castAs<Loc>(), 36170b57cec5SDimitry Andric Val, LC, /* notifyChanges = */ !atDeclInit); 36180b57cec5SDimitry Andric 36190b57cec5SDimitry Andric const MemRegion *LocReg = nullptr; 3620bdd1243dSDimitry Andric if (std::optional<loc::MemRegionVal> LocRegVal = 36210b57cec5SDimitry Andric location.getAs<loc::MemRegionVal>()) { 36220b57cec5SDimitry Andric LocReg = LocRegVal->getRegion(); 36230b57cec5SDimitry Andric } 36240b57cec5SDimitry Andric 36250b57cec5SDimitry Andric const ProgramPoint L = PostStore(StoreE, LC, LocReg, nullptr); 36260b57cec5SDimitry Andric Bldr.generateNode(L, state, PredI); 36270b57cec5SDimitry Andric } 36280b57cec5SDimitry Andric } 36290b57cec5SDimitry Andric 36300b57cec5SDimitry Andric /// evalStore - Handle the semantics of a store via an assignment. 36310b57cec5SDimitry Andric /// @param Dst The node set to store generated state nodes 36320b57cec5SDimitry Andric /// @param AssignE The assignment expression if the store happens in an 36330b57cec5SDimitry Andric /// assignment. 36340b57cec5SDimitry Andric /// @param LocationE The location expression that is stored to. 36350b57cec5SDimitry Andric /// @param state The current simulation state 36360b57cec5SDimitry Andric /// @param location The location to store the value 36370b57cec5SDimitry Andric /// @param Val The value to be stored 36380b57cec5SDimitry Andric void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, 36390b57cec5SDimitry Andric const Expr *LocationE, 36400b57cec5SDimitry Andric ExplodedNode *Pred, 36410b57cec5SDimitry Andric ProgramStateRef state, SVal location, SVal Val, 36420b57cec5SDimitry Andric const ProgramPointTag *tag) { 36430b57cec5SDimitry Andric // Proceed with the store. We use AssignE as the anchor for the PostStore 36440b57cec5SDimitry Andric // ProgramPoint if it is non-NULL, and LocationE otherwise. 36450b57cec5SDimitry Andric const Expr *StoreE = AssignE ? AssignE : LocationE; 36460b57cec5SDimitry Andric 36470b57cec5SDimitry Andric // Evaluate the location (checks for bad dereferences). 36480b57cec5SDimitry Andric ExplodedNodeSet Tmp; 36490b57cec5SDimitry Andric evalLocation(Tmp, AssignE, LocationE, Pred, state, location, false); 36500b57cec5SDimitry Andric 36510b57cec5SDimitry Andric if (Tmp.empty()) 36520b57cec5SDimitry Andric return; 36530b57cec5SDimitry Andric 36540b57cec5SDimitry Andric if (location.isUndef()) 36550b57cec5SDimitry Andric return; 36560b57cec5SDimitry Andric 36570b57cec5SDimitry Andric for (const auto I : Tmp) 36580b57cec5SDimitry Andric evalBind(Dst, StoreE, I, location, Val, false); 36590b57cec5SDimitry Andric } 36600b57cec5SDimitry Andric 36610b57cec5SDimitry Andric void ExprEngine::evalLoad(ExplodedNodeSet &Dst, 36620b57cec5SDimitry Andric const Expr *NodeEx, 36630b57cec5SDimitry Andric const Expr *BoundEx, 36640b57cec5SDimitry Andric ExplodedNode *Pred, 36650b57cec5SDimitry Andric ProgramStateRef state, 36660b57cec5SDimitry Andric SVal location, 36670b57cec5SDimitry Andric const ProgramPointTag *tag, 36680b57cec5SDimitry Andric QualType LoadTy) { 366981ad6265SDimitry Andric assert(!isa<NonLoc>(location) && "location cannot be a NonLoc."); 36700b57cec5SDimitry Andric assert(NodeEx); 36710b57cec5SDimitry Andric assert(BoundEx); 36720b57cec5SDimitry Andric // Evaluate the location (checks for bad dereferences). 36730b57cec5SDimitry Andric ExplodedNodeSet Tmp; 36740b57cec5SDimitry Andric evalLocation(Tmp, NodeEx, BoundEx, Pred, state, location, true); 36750b57cec5SDimitry Andric if (Tmp.empty()) 36760b57cec5SDimitry Andric return; 36770b57cec5SDimitry Andric 36780b57cec5SDimitry Andric StmtNodeBuilder Bldr(Tmp, Dst, *currBldrCtx); 36790b57cec5SDimitry Andric if (location.isUndef()) 36800b57cec5SDimitry Andric return; 36810b57cec5SDimitry Andric 36820b57cec5SDimitry Andric // Proceed with the load. 36830b57cec5SDimitry Andric for (const auto I : Tmp) { 36840b57cec5SDimitry Andric state = I->getState(); 36850b57cec5SDimitry Andric const LocationContext *LCtx = I->getLocationContext(); 36860b57cec5SDimitry Andric 36870b57cec5SDimitry Andric SVal V = UnknownVal(); 36880b57cec5SDimitry Andric if (location.isValid()) { 36890b57cec5SDimitry Andric if (LoadTy.isNull()) 36900b57cec5SDimitry Andric LoadTy = BoundEx->getType(); 36910b57cec5SDimitry Andric V = state->getSVal(location.castAs<Loc>(), LoadTy); 36920b57cec5SDimitry Andric } 36930b57cec5SDimitry Andric 36940b57cec5SDimitry Andric Bldr.generateNode(NodeEx, I, state->BindExpr(BoundEx, LCtx, V), tag, 36950b57cec5SDimitry Andric ProgramPoint::PostLoadKind); 36960b57cec5SDimitry Andric } 36970b57cec5SDimitry Andric } 36980b57cec5SDimitry Andric 36990b57cec5SDimitry Andric void ExprEngine::evalLocation(ExplodedNodeSet &Dst, 37000b57cec5SDimitry Andric const Stmt *NodeEx, 37010b57cec5SDimitry Andric const Stmt *BoundEx, 37020b57cec5SDimitry Andric ExplodedNode *Pred, 37030b57cec5SDimitry Andric ProgramStateRef state, 37040b57cec5SDimitry Andric SVal location, 37050b57cec5SDimitry Andric bool isLoad) { 37060b57cec5SDimitry Andric StmtNodeBuilder BldrTop(Pred, Dst, *currBldrCtx); 37070b57cec5SDimitry Andric // Early checks for performance reason. 37080b57cec5SDimitry Andric if (location.isUnknown()) { 37090b57cec5SDimitry Andric return; 37100b57cec5SDimitry Andric } 37110b57cec5SDimitry Andric 37120b57cec5SDimitry Andric ExplodedNodeSet Src; 37130b57cec5SDimitry Andric BldrTop.takeNodes(Pred); 37140b57cec5SDimitry Andric StmtNodeBuilder Bldr(Pred, Src, *currBldrCtx); 37150b57cec5SDimitry Andric if (Pred->getState() != state) { 37160b57cec5SDimitry Andric // Associate this new state with an ExplodedNode. 37170b57cec5SDimitry Andric // FIXME: If I pass null tag, the graph is incorrect, e.g for 37180b57cec5SDimitry Andric // int *p; 37190b57cec5SDimitry Andric // p = 0; 37200b57cec5SDimitry Andric // *p = 0xDEADBEEF; 37210b57cec5SDimitry Andric // "p = 0" is not noted as "Null pointer value stored to 'p'" but 37220b57cec5SDimitry Andric // instead "int *p" is noted as 37230b57cec5SDimitry Andric // "Variable 'p' initialized to a null pointer value" 37240b57cec5SDimitry Andric 37250b57cec5SDimitry Andric static SimpleProgramPointTag tag(TagProviderName, "Location"); 37260b57cec5SDimitry Andric Bldr.generateNode(NodeEx, Pred, state, &tag); 37270b57cec5SDimitry Andric } 37280b57cec5SDimitry Andric ExplodedNodeSet Tmp; 37290b57cec5SDimitry Andric getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad, 37300b57cec5SDimitry Andric NodeEx, BoundEx, *this); 37310b57cec5SDimitry Andric BldrTop.addNodes(Tmp); 37320b57cec5SDimitry Andric } 37330b57cec5SDimitry Andric 37340b57cec5SDimitry Andric std::pair<const ProgramPointTag *, const ProgramPointTag*> 37350b57cec5SDimitry Andric ExprEngine::geteagerlyAssumeBinOpBifurcationTags() { 37360b57cec5SDimitry Andric static SimpleProgramPointTag 37370b57cec5SDimitry Andric eagerlyAssumeBinOpBifurcationTrue(TagProviderName, 37380b57cec5SDimitry Andric "Eagerly Assume True"), 37390b57cec5SDimitry Andric eagerlyAssumeBinOpBifurcationFalse(TagProviderName, 37400b57cec5SDimitry Andric "Eagerly Assume False"); 37410b57cec5SDimitry Andric return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue, 37420b57cec5SDimitry Andric &eagerlyAssumeBinOpBifurcationFalse); 37430b57cec5SDimitry Andric } 37440b57cec5SDimitry Andric 37450b57cec5SDimitry Andric void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, 37460b57cec5SDimitry Andric ExplodedNodeSet &Src, 37470b57cec5SDimitry Andric const Expr *Ex) { 37480b57cec5SDimitry Andric StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx); 37490b57cec5SDimitry Andric 37500b57cec5SDimitry Andric for (const auto Pred : Src) { 37510b57cec5SDimitry Andric // Test if the previous node was as the same expression. This can happen 37520b57cec5SDimitry Andric // when the expression fails to evaluate to anything meaningful and 37530b57cec5SDimitry Andric // (as an optimization) we don't generate a node. 37540b57cec5SDimitry Andric ProgramPoint P = Pred->getLocation(); 37550b57cec5SDimitry Andric if (!P.getAs<PostStmt>() || P.castAs<PostStmt>().getStmt() != Ex) { 37560b57cec5SDimitry Andric continue; 37570b57cec5SDimitry Andric } 37580b57cec5SDimitry Andric 37590b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 37600b57cec5SDimitry Andric SVal V = state->getSVal(Ex, Pred->getLocationContext()); 3761bdd1243dSDimitry Andric std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>(); 37620b57cec5SDimitry Andric if (SEV && SEV->isExpression()) { 37630b57cec5SDimitry Andric const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags = 37640b57cec5SDimitry Andric geteagerlyAssumeBinOpBifurcationTags(); 37650b57cec5SDimitry Andric 37660b57cec5SDimitry Andric ProgramStateRef StateTrue, StateFalse; 37670b57cec5SDimitry Andric std::tie(StateTrue, StateFalse) = state->assume(*SEV); 37680b57cec5SDimitry Andric 37690b57cec5SDimitry Andric // First assume that the condition is true. 37700b57cec5SDimitry Andric if (StateTrue) { 37710b57cec5SDimitry Andric SVal Val = svalBuilder.makeIntVal(1U, Ex->getType()); 37720b57cec5SDimitry Andric StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val); 37730b57cec5SDimitry Andric Bldr.generateNode(Ex, Pred, StateTrue, tags.first); 37740b57cec5SDimitry Andric } 37750b57cec5SDimitry Andric 37760b57cec5SDimitry Andric // Next, assume that the condition is false. 37770b57cec5SDimitry Andric if (StateFalse) { 37780b57cec5SDimitry Andric SVal Val = svalBuilder.makeIntVal(0U, Ex->getType()); 37790b57cec5SDimitry Andric StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val); 37800b57cec5SDimitry Andric Bldr.generateNode(Ex, Pred, StateFalse, tags.second); 37810b57cec5SDimitry Andric } 37820b57cec5SDimitry Andric } 37830b57cec5SDimitry Andric } 37840b57cec5SDimitry Andric } 37850b57cec5SDimitry Andric 37860b57cec5SDimitry Andric void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, 37870b57cec5SDimitry Andric ExplodedNodeSet &Dst) { 37880b57cec5SDimitry Andric StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); 37890b57cec5SDimitry Andric // We have processed both the inputs and the outputs. All of the outputs 37900b57cec5SDimitry Andric // should evaluate to Locs. Nuke all of their values. 37910b57cec5SDimitry Andric 37920b57cec5SDimitry Andric // FIXME: Some day in the future it would be nice to allow a "plug-in" 37930b57cec5SDimitry Andric // which interprets the inline asm and stores proper results in the 37940b57cec5SDimitry Andric // outputs. 37950b57cec5SDimitry Andric 37960b57cec5SDimitry Andric ProgramStateRef state = Pred->getState(); 37970b57cec5SDimitry Andric 37980b57cec5SDimitry Andric for (const Expr *O : A->outputs()) { 37990b57cec5SDimitry Andric SVal X = state->getSVal(O, Pred->getLocationContext()); 380081ad6265SDimitry Andric assert(!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef. 38010b57cec5SDimitry Andric 3802bdd1243dSDimitry Andric if (std::optional<Loc> LV = X.getAs<Loc>()) 38030b57cec5SDimitry Andric state = state->bindLoc(*LV, UnknownVal(), Pred->getLocationContext()); 38040b57cec5SDimitry Andric } 38050b57cec5SDimitry Andric 38060b57cec5SDimitry Andric Bldr.generateNode(A, Pred, state); 38070b57cec5SDimitry Andric } 38080b57cec5SDimitry Andric 38090b57cec5SDimitry Andric void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred, 38100b57cec5SDimitry Andric ExplodedNodeSet &Dst) { 38110b57cec5SDimitry Andric StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); 38120b57cec5SDimitry Andric Bldr.generateNode(A, Pred, Pred->getState()); 38130b57cec5SDimitry Andric } 38140b57cec5SDimitry Andric 38150b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 38160b57cec5SDimitry Andric // Visualization. 38170b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 38180b57cec5SDimitry Andric 38190b57cec5SDimitry Andric namespace llvm { 38200b57cec5SDimitry Andric 38210b57cec5SDimitry Andric template<> 38220b57cec5SDimitry Andric struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits { 38230b57cec5SDimitry Andric DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} 38240b57cec5SDimitry Andric 38250b57cec5SDimitry Andric static bool nodeHasBugReport(const ExplodedNode *N) { 38260b57cec5SDimitry Andric BugReporter &BR = static_cast<ExprEngine &>( 38270b57cec5SDimitry Andric N->getState()->getStateManager().getOwningEngine()).getBugReporter(); 38280b57cec5SDimitry Andric 382906c3fb27SDimitry Andric for (const auto &Class : BR.equivalenceClasses()) { 383006c3fb27SDimitry Andric for (const auto &Report : Class.getReports()) { 383106c3fb27SDimitry Andric const auto *PR = dyn_cast<PathSensitiveBugReport>(Report.get()); 3832a7dea167SDimitry Andric if (!PR) 3833a7dea167SDimitry Andric continue; 3834a7dea167SDimitry Andric const ExplodedNode *EN = PR->getErrorNode(); 3835a7dea167SDimitry Andric if (EN->getState() == N->getState() && 3836a7dea167SDimitry Andric EN->getLocation() == N->getLocation()) 38370b57cec5SDimitry Andric return true; 38380b57cec5SDimitry Andric } 38390b57cec5SDimitry Andric } 38400b57cec5SDimitry Andric return false; 38410b57cec5SDimitry Andric } 38420b57cec5SDimitry Andric 38430b57cec5SDimitry Andric /// \p PreCallback: callback before break. 38440b57cec5SDimitry Andric /// \p PostCallback: callback after break. 3845fe6060f1SDimitry Andric /// \p Stop: stop iteration if returns @c true 3846fe6060f1SDimitry Andric /// \return Whether @c Stop ever returned @c true. 38470b57cec5SDimitry Andric static bool traverseHiddenNodes( 38480b57cec5SDimitry Andric const ExplodedNode *N, 38490b57cec5SDimitry Andric llvm::function_ref<void(const ExplodedNode *)> PreCallback, 38500b57cec5SDimitry Andric llvm::function_ref<void(const ExplodedNode *)> PostCallback, 38510b57cec5SDimitry Andric llvm::function_ref<bool(const ExplodedNode *)> Stop) { 38520b57cec5SDimitry Andric while (true) { 3853a7dea167SDimitry Andric PreCallback(N); 3854a7dea167SDimitry Andric if (Stop(N)) 38550b57cec5SDimitry Andric return true; 38560b57cec5SDimitry Andric 3857e8d8bef9SDimitry Andric if (N->succ_size() != 1 || !isNodeHidden(N->getFirstSucc(), nullptr)) 38580b57cec5SDimitry Andric break; 3859a7dea167SDimitry Andric PostCallback(N); 38600b57cec5SDimitry Andric 3861a7dea167SDimitry Andric N = N->getFirstSucc(); 38620b57cec5SDimitry Andric } 38630b57cec5SDimitry Andric return false; 38640b57cec5SDimitry Andric } 38650b57cec5SDimitry Andric 3866e8d8bef9SDimitry Andric static bool isNodeHidden(const ExplodedNode *N, const ExplodedGraph *G) { 38670b57cec5SDimitry Andric return N->isTrivial(); 38680b57cec5SDimitry Andric } 38690b57cec5SDimitry Andric 38700b57cec5SDimitry Andric static std::string getNodeLabel(const ExplodedNode *N, ExplodedGraph *G){ 38710b57cec5SDimitry Andric std::string Buf; 38720b57cec5SDimitry Andric llvm::raw_string_ostream Out(Buf); 38730b57cec5SDimitry Andric 38740b57cec5SDimitry Andric const bool IsDot = true; 38750b57cec5SDimitry Andric const unsigned int Space = 1; 38760b57cec5SDimitry Andric ProgramStateRef State = N->getState(); 38770b57cec5SDimitry Andric 3878a7dea167SDimitry Andric Out << "{ \"state_id\": " << State->getID() 38790b57cec5SDimitry Andric << ",\\l"; 38800b57cec5SDimitry Andric 38810b57cec5SDimitry Andric Indent(Out, Space, IsDot) << "\"program_points\": [\\l"; 38820b57cec5SDimitry Andric 38830b57cec5SDimitry Andric // Dump program point for all the previously skipped nodes. 38840b57cec5SDimitry Andric traverseHiddenNodes( 38850b57cec5SDimitry Andric N, 38860b57cec5SDimitry Andric [&](const ExplodedNode *OtherNode) { 38870b57cec5SDimitry Andric Indent(Out, Space + 1, IsDot) << "{ "; 38880b57cec5SDimitry Andric OtherNode->getLocation().printJson(Out, /*NL=*/"\\l"); 38890b57cec5SDimitry Andric Out << ", \"tag\": "; 38900b57cec5SDimitry Andric if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag()) 3891bdd1243dSDimitry Andric Out << '\"' << Tag->getTagDescription() << '\"'; 38920b57cec5SDimitry Andric else 3893a7dea167SDimitry Andric Out << "null"; 3894a7dea167SDimitry Andric Out << ", \"node_id\": " << OtherNode->getID() << 3895a7dea167SDimitry Andric ", \"is_sink\": " << OtherNode->isSink() << 3896a7dea167SDimitry Andric ", \"has_report\": " << nodeHasBugReport(OtherNode) << " }"; 38970b57cec5SDimitry Andric }, 38980b57cec5SDimitry Andric // Adds a comma and a new-line between each program point. 38990b57cec5SDimitry Andric [&](const ExplodedNode *) { Out << ",\\l"; }, 39000b57cec5SDimitry Andric [&](const ExplodedNode *) { return false; }); 39010b57cec5SDimitry Andric 39020b57cec5SDimitry Andric Out << "\\l"; // Adds a new-line to the last program point. 39030b57cec5SDimitry Andric Indent(Out, Space, IsDot) << "],\\l"; 39040b57cec5SDimitry Andric 39050b57cec5SDimitry Andric State->printDOT(Out, N->getLocationContext(), Space); 39060b57cec5SDimitry Andric 39070b57cec5SDimitry Andric Out << "\\l}\\l"; 39080fca6ea1SDimitry Andric return Buf; 39090b57cec5SDimitry Andric } 39100b57cec5SDimitry Andric }; 39110b57cec5SDimitry Andric 39120b57cec5SDimitry Andric } // namespace llvm 39130b57cec5SDimitry Andric 39140b57cec5SDimitry Andric void ExprEngine::ViewGraph(bool trim) { 39150b57cec5SDimitry Andric std::string Filename = DumpGraph(trim); 39160b57cec5SDimitry Andric llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT); 39170b57cec5SDimitry Andric } 39180b57cec5SDimitry Andric 39190b57cec5SDimitry Andric void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode *> Nodes) { 39200b57cec5SDimitry Andric std::string Filename = DumpGraph(Nodes); 39210b57cec5SDimitry Andric llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT); 39220b57cec5SDimitry Andric } 39230b57cec5SDimitry Andric 39240b57cec5SDimitry Andric std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) { 39250b57cec5SDimitry Andric if (trim) { 39260b57cec5SDimitry Andric std::vector<const ExplodedNode *> Src; 39270b57cec5SDimitry Andric 39280b57cec5SDimitry Andric // Iterate through the reports and get their nodes. 392906c3fb27SDimitry Andric for (const auto &Class : BR.equivalenceClasses()) { 3930a7dea167SDimitry Andric const auto *R = 393106c3fb27SDimitry Andric dyn_cast<PathSensitiveBugReport>(Class.getReports()[0].get()); 3932a7dea167SDimitry Andric if (!R) 3933a7dea167SDimitry Andric continue; 3934a7dea167SDimitry Andric const auto *N = const_cast<ExplodedNode *>(R->getErrorNode()); 3935a7dea167SDimitry Andric Src.push_back(N); 39360b57cec5SDimitry Andric } 39370b57cec5SDimitry Andric return DumpGraph(Src, Filename); 393881ad6265SDimitry Andric } 393981ad6265SDimitry Andric 39400b57cec5SDimitry Andric return llvm::WriteGraph(&G, "ExprEngine", /*ShortNames=*/false, 39415ffd83dbSDimitry Andric /*Title=*/"Exploded Graph", 39425ffd83dbSDimitry Andric /*Filename=*/std::string(Filename)); 39430b57cec5SDimitry Andric } 39440b57cec5SDimitry Andric 39450b57cec5SDimitry Andric std::string ExprEngine::DumpGraph(ArrayRef<const ExplodedNode *> Nodes, 39460b57cec5SDimitry Andric StringRef Filename) { 39470b57cec5SDimitry Andric std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes)); 39480b57cec5SDimitry Andric 39490b57cec5SDimitry Andric if (!TrimmedG.get()) { 39500b57cec5SDimitry Andric llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; 3951e8d8bef9SDimitry Andric return ""; 395281ad6265SDimitry Andric } 395381ad6265SDimitry Andric 39540b57cec5SDimitry Andric return llvm::WriteGraph(TrimmedG.get(), "TrimmedExprEngine", 39550b57cec5SDimitry Andric /*ShortNames=*/false, 39560b57cec5SDimitry Andric /*Title=*/"Trimmed Exploded Graph", 39575ffd83dbSDimitry Andric /*Filename=*/std::string(Filename)); 39580b57cec5SDimitry Andric } 39590b57cec5SDimitry Andric 39600b57cec5SDimitry Andric void *ProgramStateTrait<ReplayWithoutInlining>::GDMIndex() { 39610b57cec5SDimitry Andric static int index = 0; 39620b57cec5SDimitry Andric return &index; 39630b57cec5SDimitry Andric } 39645ffd83dbSDimitry Andric 39655ffd83dbSDimitry Andric void ExprEngine::anchor() { } 3966