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