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