clang 23.0.0git
Environment.cpp
Go to the documentation of this file.
1//===- Environment.cpp - Map from Stmt* to Locations/Values ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defined the Environment and EnvironmentManager classes.
10//
11//===----------------------------------------------------------------------===//
12
14#include "clang/AST/Expr.h"
15#include "clang/AST/ExprCXX.h"
17#include "clang/AST/Stmt.h"
18#include "clang/AST/StmtObjC.h"
21#include "clang/Basic/LLVM.h"
27#include "llvm/ADT/ImmutableMap.h"
28#include "llvm/ADT/SmallPtrSet.h"
29#include "llvm/Support/ErrorHandling.h"
30#include "llvm/Support/raw_ostream.h"
31#include <cassert>
32
33using namespace clang;
34using namespace ento;
35
36static const Expr *ignoreTransparentExprs(const Expr *E) {
37 E = E->IgnoreParens();
38
39 switch (E->getStmtClass()) {
40 case Stmt::OpaqueValueExprClass:
41 if (const Expr *SE = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
42 E = SE;
43 break;
44 }
45 return E;
46 case Stmt::ExprWithCleanupsClass:
47 E = cast<ExprWithCleanups>(E)->getSubExpr();
48 break;
49 case Stmt::ConstantExprClass:
50 E = cast<ConstantExpr>(E)->getSubExpr();
51 break;
52 case Stmt::CXXBindTemporaryExprClass:
53 E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
54 break;
55 case Stmt::SubstNonTypeTemplateParmExprClass:
56 E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
57 break;
58 default:
59 // This is the base case: we can't look through more than we already have.
60 return E;
61 }
62
63 return ignoreTransparentExprs(E);
64}
65
66static const Stmt *ignoreTransparentExprs(const Stmt *S) {
67 if (const auto *E = dyn_cast<Expr>(S))
68 return ignoreTransparentExprs(E);
69 return S;
70}
71
73 : std::pair<const Stmt *,
75 L ? L->getStackFrame()
76 : nullptr) {}
77
78SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
79 const SVal* X = ExprBindings.lookup(E);
80 if (X) {
81 SVal V = *X;
82 return V;
83 }
84 return UnknownVal();
85}
86
88 SValBuilder& svalBuilder) const {
89 const Stmt *S = Entry.getStmt();
90 assert(!isa<ObjCForCollectionStmt>(S) &&
91 "Use ExprEngine::hasMoreIteration()!");
92 assert((isa<Expr, ReturnStmt>(S)) &&
93 "Environment can only argue about Exprs, since only they express "
94 "a value! Any non-expression statement stored in Environment is a "
95 "result of a hack!");
96 const LocationContext *LCtx = Entry.getLocationContext();
97
98 switch (S->getStmtClass()) {
99 case Stmt::CXXBindTemporaryExprClass:
100 case Stmt::ExprWithCleanupsClass:
101 case Stmt::GenericSelectionExprClass:
102 case Stmt::ConstantExprClass:
103 case Stmt::ParenExprClass:
104 case Stmt::SubstNonTypeTemplateParmExprClass:
105 llvm_unreachable("Should have been handled by ignoreTransparentExprs");
106
107 case Stmt::AddrLabelExprClass:
108 case Stmt::CharacterLiteralClass:
109 case Stmt::CXXBoolLiteralExprClass:
110 case Stmt::CXXScalarValueInitExprClass:
111 case Stmt::ImplicitValueInitExprClass:
112 case Stmt::IntegerLiteralClass:
113 case Stmt::ObjCBoolLiteralExprClass:
114 case Stmt::CXXNullPtrLiteralExprClass:
115 case Stmt::ObjCStringLiteralClass:
116 case Stmt::StringLiteralClass:
117 case Stmt::TypeTraitExprClass:
118 case Stmt::SizeOfPackExprClass:
119 case Stmt::PredefinedExprClass:
120 // Known constants; defer to SValBuilder.
121 return *svalBuilder.getConstantVal(cast<Expr>(S));
122
123 case Stmt::ReturnStmtClass: {
124 // FIXME: Move this logic to ExprEngine::processCallExit (the only location
125 // passes a ReturnStmt to this method) and then there will be no need to
126 // accept non-expression statements in getSVal (in fact, it will be
127 // possible to change the first member of EnvironmentEntry from const Stmt*
128 // to const Expr*).
129 const auto *RS = cast<ReturnStmt>(S);
130 if (const Expr *RE = RS->getRetValue())
131 return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
132 return UndefinedVal();
133 }
134
135 // Handle all other Stmt* using a lookup.
136 default:
137 return lookupExpr(EnvironmentEntry(S, LCtx));
138 }
139}
140
142 const EnvironmentEntry &E,
143 SVal V,
144 bool Invalidate) {
145 if (V.isUnknown()) {
146 if (Invalidate)
147 return Environment(F.remove(Env.ExprBindings, E));
148 else
149 return Env;
150 }
151 return Environment(F.add(Env.ExprBindings, E, V));
152}
153
154namespace {
155
156class MarkLiveCallback final : public SymbolVisitor {
157 SymbolReaper &SymReaper;
158
159public:
160 MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
161
162 bool VisitSymbol(SymbolRef sym) override {
163 SymReaper.markLive(sym);
164 return true;
165 }
166
167 bool VisitMemRegion(const MemRegion *R) override {
168 SymReaper.markLive(R);
169 return true;
170 }
171};
172
173} // namespace
174
175// removeDeadBindings:
176// - Remove subexpression bindings.
177// - Remove dead block expression bindings.
178// - Keep live block expression bindings:
179// - Mark their reachable symbols live in SymbolReaper,
180// see ScanReachableSymbols.
181// - Mark the region in DRoots if the binding is a loc::MemRegionVal.
184 SymbolReaper &SymReaper,
185 ProgramStateRef ST) {
186 // We construct a new Environment object entirely, as this is cheaper than
187 // individually removing all the subexpression bindings (which will greatly
188 // outnumber block-level expression bindings).
190
191 MarkLiveCallback CB(SymReaper);
192 ScanReachableSymbols RSScaner(ST, CB);
193
194 llvm::ImmutableMapRef<EnvironmentEntry, SVal>
195 EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
196 F.getTreeFactory());
197
198 // Iterate over the block-expr bindings.
199 for (Environment::iterator I = Env.begin(), End = Env.end(); I != End; ++I) {
200 const EnvironmentEntry &BlkExpr = I.getKey();
201 SVal X = I.getData();
202
203 const Expr *E = dyn_cast<Expr>(BlkExpr.getStmt());
204 if (!E)
205 continue;
206
207 if (SymReaper.isLive(E, BlkExpr.getLocationContext())) {
208 // Copy the binding to the new map.
209 EBMapRef = EBMapRef.add(BlkExpr, X);
210
211 // Mark all symbols in the block expr's value live.
212 RSScaner.scan(X);
213 }
214 }
215
216 NewEnv.ExprBindings = EBMapRef.asImmutableMap();
217 return NewEnv;
218}
219
220void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
221 const LocationContext *LCtx, const char *NL,
222 unsigned int Space, bool IsDot) const {
223 Indent(Out, Space, IsDot) << "\"environment\": ";
224
225 if (ExprBindings.isEmpty()) {
226 Out << "null," << NL;
227 return;
228 }
229
230 ++Space;
231 if (!LCtx) {
232 // Find the freshest location context.
234 for (const auto &I : *this) {
235 const LocationContext *LC = I.first.getLocationContext();
236 if (FoundContexts.count(LC) == 0) {
237 // This context is fresher than all other contexts so far.
238 LCtx = LC;
239 for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent())
240 FoundContexts.insert(LCI);
241 }
242 }
243 }
244
245 assert(LCtx);
246
247 Out << "{ \"pointer\": \"" << (const void *)LCtx->getStackFrame()
248 << "\", \"items\": [" << NL;
250
251 LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
252 // LCtx items begin
253 bool HasItem = false;
254 unsigned int InnerSpace = Space + 1;
255
256 // Store the last ExprBinding which we will print.
257 BindingsTy::iterator LastI = ExprBindings.end();
258 for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
259 ++I) {
260 if (I->first.getLocationContext() != LC)
261 continue;
262
263 if (!HasItem) {
264 HasItem = true;
265 Out << '[' << NL;
266 }
267
268 const Stmt *S = I->first.getStmt();
269 (void)S;
270 assert(S != nullptr && "Expected non-null Stmt");
271
272 LastI = I;
273 }
274
275 for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
276 ++I) {
277 if (I->first.getLocationContext() != LC)
278 continue;
279
280 const Stmt *S = I->first.getStmt();
281 Indent(Out, InnerSpace, IsDot)
282 << "{ \"stmt_id\": " << S->getID(Ctx) << ", \"kind\": \""
283 << S->getStmtClassName() << "\", \"pretty\": ";
284 S->printJson(Out, nullptr, PP, /*AddQuotes=*/true);
285
286 Out << ", \"value\": ";
287 I->second.printJson(Out, /*AddQuotes=*/true);
288
289 Out << " }";
290
291 if (I != LastI)
292 Out << ',';
293 Out << NL;
294 }
295
296 if (HasItem)
297 Indent(Out, --InnerSpace, IsDot) << ']';
298 else
299 Out << "null ";
300 });
301
302 Indent(Out, --Space, IsDot) << "]}," << NL;
303}
#define V(N, I)
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static const Expr * ignoreTransparentExprs(const Expr *E)
Defines the clang::Expr interface and subclasses for C++ expressions.
#define X(type, name)
Definition Value.h:97
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the Objective-C statement AST node classes.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:227
const clang::PrintingPolicy & getPrintingPolicy() const
Definition ASTContext.h:858
This represents one expression.
Definition Expr.h:112
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3086
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
void printJson(raw_ostream &Out, const char *NL="\n", unsigned int Space=0, bool IsDot=false, std::function< void(const LocationContext *)> printMoreInfoPerContext=[](const LocationContext *) {}) const
Prints out the call stack in json format.
It represents a stack frame of the call stack (based on CallEvent).
Stmt - This represents one statement.
Definition Stmt.h:86
void printJson(raw_ostream &Out, PrinterHelper *Helper, const PrintingPolicy &Policy, bool AddQuotes) const
Pretty-prints in JSON format.
StmtClass getStmtClass() const
Definition Stmt.h:1499
const char * getStmtClassName() const
Definition Stmt.cpp:86
int64_t getID(const ASTContext &Context) const
Definition Stmt.cpp:379
An entry in the environment consists of a Stmt and an LocationContext.
Definition Environment.h:41
const Stmt * getStmt() const
Definition Environment.h:45
EnvironmentEntry(const Stmt *s, const LocationContext *L)
const LocationContext * getLocationContext() const
Definition Environment.h:46
Environment bindExpr(Environment Env, const EnvironmentEntry &E, SVal V, bool Invalidate)
Bind a symbolic value to the given environment entry.
Environment removeDeadBindings(Environment Env, SymbolReaper &SymReaper, ProgramStateRef state)
An immutable map from EnvironmentEntries to SVals.
Definition Environment.h:61
SVal getSVal(const EnvironmentEntry &E, SValBuilder &svalBuilder) const
Fetches the current binding of the expression in the Environment.
void printJson(raw_ostream &Out, const ASTContext &Ctx, const LocationContext *LCtx=nullptr, const char *NL="\n", unsigned int Space=0, bool IsDot=false) const
iterator end() const
Definition Environment.h:77
iterator begin() const
Definition Environment.h:76
BindingsTy::iterator iterator
Definition Environment.h:74
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:98
std::optional< SVal > getConstantVal(const Expr *E)
Returns the value of E, if it can be determined in a non-path-sensitive manner.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
A utility class that visits the reachable symbols using a custom SymbolVisitor.
bool scan(nonloc::LazyCompoundVal val)
A class responsible for cleaning up unused symbols.
bool isLive(SymbolRef sym)
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
raw_ostream & Indent(raw_ostream &Out, const unsigned int Space, bool IsDot)
Definition JsonSupport.h:21
U cast(CodeGen::Address addr)
Definition Address.h:327
Describes how types, statements, expressions, and declarations should be printed.