clang 20.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"
28#include "llvm/ADT/ImmutableMap.h"
29#include "llvm/ADT/SmallPtrSet.h"
30#include "llvm/Support/Casting.h"
31#include "llvm/Support/ErrorHandling.h"
32#include "llvm/Support/raw_ostream.h"
33#include <cassert>
34
35using namespace clang;
36using namespace ento;
37
38static const Expr *ignoreTransparentExprs(const Expr *E) {
39 E = E->IgnoreParens();
40
41 switch (E->getStmtClass()) {
42 case Stmt::OpaqueValueExprClass:
43 if (const Expr *SE = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
44 E = SE;
45 break;
46 }
47 return E;
48 case Stmt::ExprWithCleanupsClass:
49 E = cast<ExprWithCleanups>(E)->getSubExpr();
50 break;
51 case Stmt::ConstantExprClass:
52 E = cast<ConstantExpr>(E)->getSubExpr();
53 break;
54 case Stmt::CXXBindTemporaryExprClass:
55 E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
56 break;
57 case Stmt::SubstNonTypeTemplateParmExprClass:
58 E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
59 break;
60 default:
61 // This is the base case: we can't look through more than we already have.
62 return E;
63 }
64
66}
67
68static const Stmt *ignoreTransparentExprs(const Stmt *S) {
69 if (const auto *E = dyn_cast<Expr>(S))
71 return S;
72}
73
75 : std::pair<const Stmt *,
77 L ? L->getStackFrame()
78 : nullptr) {}
79
80SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
81 const SVal* X = ExprBindings.lookup(E);
82 if (X) {
83 SVal V = *X;
84 return V;
85 }
86 return UnknownVal();
87}
88
90 SValBuilder& svalBuilder) const {
91 const Stmt *S = Entry.getStmt();
92 assert(!isa<ObjCForCollectionStmt>(S) &&
93 "Use ExprEngine::hasMoreIteration()!");
94 assert((isa<Expr, ReturnStmt>(S)) &&
95 "Environment can only argue about Exprs, since only they express "
96 "a value! Any non-expression statement stored in Environment is a "
97 "result of a hack!");
98 const LocationContext *LCtx = Entry.getLocationContext();
99
100 switch (S->getStmtClass()) {
101 case Stmt::CXXBindTemporaryExprClass:
102 case Stmt::ExprWithCleanupsClass:
103 case Stmt::GenericSelectionExprClass:
104 case Stmt::ConstantExprClass:
105 case Stmt::ParenExprClass:
106 case Stmt::SubstNonTypeTemplateParmExprClass:
107 llvm_unreachable("Should have been handled by ignoreTransparentExprs");
108
109 case Stmt::AddrLabelExprClass:
110 case Stmt::CharacterLiteralClass:
111 case Stmt::CXXBoolLiteralExprClass:
112 case Stmt::CXXScalarValueInitExprClass:
113 case Stmt::ImplicitValueInitExprClass:
114 case Stmt::IntegerLiteralClass:
115 case Stmt::ObjCBoolLiteralExprClass:
116 case Stmt::CXXNullPtrLiteralExprClass:
117 case Stmt::ObjCStringLiteralClass:
118 case Stmt::StringLiteralClass:
119 case Stmt::TypeTraitExprClass:
120 case Stmt::SizeOfPackExprClass:
121 case Stmt::PredefinedExprClass:
122 // Known constants; defer to SValBuilder.
123 return *svalBuilder.getConstantVal(cast<Expr>(S));
124
125 case Stmt::ReturnStmtClass: {
126 const auto *RS = cast<ReturnStmt>(S);
127 if (const Expr *RE = RS->getRetValue())
128 return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
129 return UndefinedVal();
130 }
131
132 // Handle all other Stmt* using a lookup.
133 default:
134 return lookupExpr(EnvironmentEntry(S, LCtx));
135 }
136}
137
139 const EnvironmentEntry &E,
140 SVal V,
141 bool Invalidate) {
142 if (V.isUnknown()) {
143 if (Invalidate)
144 return Environment(F.remove(Env.ExprBindings, E));
145 else
146 return Env;
147 }
148 return Environment(F.add(Env.ExprBindings, E, V));
149}
150
151namespace {
152
153class MarkLiveCallback final : public SymbolVisitor {
154 SymbolReaper &SymReaper;
155
156public:
157 MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
158
159 bool VisitSymbol(SymbolRef sym) override {
160 SymReaper.markLive(sym);
161 return true;
162 }
163
164 bool VisitMemRegion(const MemRegion *R) override {
165 SymReaper.markLive(R);
166 return true;
167 }
168};
169
170} // namespace
171
172// removeDeadBindings:
173// - Remove subexpression bindings.
174// - Remove dead block expression bindings.
175// - Keep live block expression bindings:
176// - Mark their reachable symbols live in SymbolReaper,
177// see ScanReachableSymbols.
178// - Mark the region in DRoots if the binding is a loc::MemRegionVal.
181 SymbolReaper &SymReaper,
182 ProgramStateRef ST) {
183 // We construct a new Environment object entirely, as this is cheaper than
184 // individually removing all the subexpression bindings (which will greatly
185 // outnumber block-level expression bindings).
187
188 MarkLiveCallback CB(SymReaper);
189 ScanReachableSymbols RSScaner(ST, CB);
190
191 llvm::ImmutableMapRef<EnvironmentEntry, SVal>
192 EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
193 F.getTreeFactory());
194
195 // Iterate over the block-expr bindings.
196 for (Environment::iterator I = Env.begin(), End = Env.end(); I != End; ++I) {
197 const EnvironmentEntry &BlkExpr = I.getKey();
198 SVal X = I.getData();
199
200 const Expr *E = dyn_cast<Expr>(BlkExpr.getStmt());
201 if (!E)
202 continue;
203
204 if (SymReaper.isLive(E, BlkExpr.getLocationContext())) {
205 // Copy the binding to the new map.
206 EBMapRef = EBMapRef.add(BlkExpr, X);
207
208 // Mark all symbols in the block expr's value live.
209 RSScaner.scan(X);
210 }
211 }
212
213 NewEnv.ExprBindings = EBMapRef.asImmutableMap();
214 return NewEnv;
215}
216
217void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
218 const LocationContext *LCtx, const char *NL,
219 unsigned int Space, bool IsDot) const {
220 Indent(Out, Space, IsDot) << "\"environment\": ";
221
222 if (ExprBindings.isEmpty()) {
223 Out << "null," << NL;
224 return;
225 }
226
227 ++Space;
228 if (!LCtx) {
229 // Find the freshest location context.
231 for (const auto &I : *this) {
232 const LocationContext *LC = I.first.getLocationContext();
233 if (FoundContexts.count(LC) == 0) {
234 // This context is fresher than all other contexts so far.
235 LCtx = LC;
236 for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent())
237 FoundContexts.insert(LCI);
238 }
239 }
240 }
241
242 assert(LCtx);
243
244 Out << "{ \"pointer\": \"" << (const void *)LCtx->getStackFrame()
245 << "\", \"items\": [" << NL;
247
248 LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
249 // LCtx items begin
250 bool HasItem = false;
251 unsigned int InnerSpace = Space + 1;
252
253 // Store the last ExprBinding which we will print.
254 BindingsTy::iterator LastI = ExprBindings.end();
255 for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
256 ++I) {
257 if (I->first.getLocationContext() != LC)
258 continue;
259
260 if (!HasItem) {
261 HasItem = true;
262 Out << '[' << NL;
263 }
264
265 const Stmt *S = I->first.getStmt();
266 (void)S;
267 assert(S != nullptr && "Expected non-null Stmt");
268
269 LastI = I;
270 }
271
272 for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
273 ++I) {
274 if (I->first.getLocationContext() != LC)
275 continue;
276
277 const Stmt *S = I->first.getStmt();
278 Indent(Out, InnerSpace, IsDot)
279 << "{ \"stmt_id\": " << S->getID(Ctx) << ", \"kind\": \""
280 << S->getStmtClassName() << "\", \"pretty\": ";
281 S->printJson(Out, nullptr, PP, /*AddQuotes=*/true);
282
283 Out << ", \"value\": ";
284 I->second.printJson(Out, /*AddQuotes=*/true);
285
286 Out << " }";
287
288 if (I != LastI)
289 Out << ',';
290 Out << NL;
291 }
292
293 if (HasItem)
294 Indent(Out, --InnerSpace, IsDot) << ']';
295 else
296 Out << "null ";
297 });
298
299 Indent(Out, --Space, IsDot) << "]}," << NL;
300}
#define V(N, I)
Definition: ASTContext.h:3341
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Expr * E
static const Expr * ignoreTransparentExprs(const Expr *E)
Definition: Environment.cpp:38
Defines the clang::Expr interface and subclasses for C++ expressions.
const Environment & Env
Definition: HTMLLogger.cpp:148
#define X(type, name)
Definition: Value.h:143
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::LangOptions interface.
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:187
const clang::PrintingPolicy & getPrintingPolicy() const
Definition: ASTContext.h:713
This represents one expression.
Definition: Expr.h:110
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3066
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:84
StmtClass getStmtClass() const
Definition: Stmt.h:1363
An entry in the environment consists of a Stmt and an LocationContext.
Definition: Environment.h:36
const Stmt * getStmt() const
Definition: Environment.h:40
EnvironmentEntry(const Stmt *s, const LocationContext *L)
Definition: Environment.cpp:74
const LocationContext * getLocationContext() const
Definition: Environment.h:41
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 EnvironemntEntries to SVals.
Definition: Environment.h:56
SVal getSVal(const EnvironmentEntry &E, SValBuilder &svalBuilder) const
Fetches the current binding of the expression in the Environment.
Definition: Environment.cpp:89
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:72
iterator begin() const
Definition: Environment.h:71
BindingsTy::iterator iterator
Definition: Environment.h:69
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:97
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:55
A utility class that visits the reachable symbols using a custom SymbolVisitor.
Definition: ProgramState.h:885
bool scan(nonloc::LazyCompoundVal val)
Symbolic value.
Definition: SymExpr.h:30
A class responsible for cleaning up unused symbols.
bool isLive(SymbolRef sym)
The JSON file list parser is used to communicate input to InstallAPI.
Describes how types, statements, expressions, and declarations should be printed.
Definition: PrettyPrinter.h:57