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
67 : std::pair<const Expr *, const StackFrame *>(ignoreTransparentExprs(E),
68 SF) {}
69
70SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
71 const SVal* X = ExprBindings.lookup(E);
72 if (X) {
73 SVal V = *X;
74 return V;
75 }
76 return UnknownVal();
77}
78
80 SValBuilder& svalBuilder) const {
81 const Expr *Ex = Entry.getExpr();
82 const StackFrame *SF = Entry.getStackFrame();
83
84 switch (Ex->getStmtClass()) {
85 case Stmt::CXXBindTemporaryExprClass:
86 case Stmt::ExprWithCleanupsClass:
87 case Stmt::GenericSelectionExprClass:
88 case Stmt::ConstantExprClass:
89 case Stmt::ParenExprClass:
90 case Stmt::SubstNonTypeTemplateParmExprClass:
91 llvm_unreachable("Should have been handled by ignoreTransparentExprs");
92
93 case Stmt::AddrLabelExprClass:
94 case Stmt::CharacterLiteralClass:
95 case Stmt::CXXBoolLiteralExprClass:
96 case Stmt::CXXScalarValueInitExprClass:
97 case Stmt::ImplicitValueInitExprClass:
98 case Stmt::IntegerLiteralClass:
99 case Stmt::ObjCBoolLiteralExprClass:
100 case Stmt::CXXNullPtrLiteralExprClass:
101 case Stmt::ObjCStringLiteralClass:
102 case Stmt::StringLiteralClass:
103 case Stmt::TypeTraitExprClass:
104 case Stmt::SizeOfPackExprClass:
105 case Stmt::PredefinedExprClass:
106 // Known constants; defer to SValBuilder.
107 return *svalBuilder.getConstantVal(Ex);
108
109 // Handle all other Expr* using a lookup.
110 default:
111 return lookupExpr(EnvironmentEntry(Ex, SF));
112 }
113}
114
116 const EnvironmentEntry &E,
117 SVal V,
118 bool Invalidate) {
119 if (V.isUnknown()) {
120 if (Invalidate)
121 return Environment(F.remove(Env.ExprBindings, E));
122 else
123 return Env;
124 }
125 return Environment(F.add(Env.ExprBindings, E, V));
126}
127
128namespace {
129
130class MarkLiveCallback final : public SymbolVisitor {
131 SymbolReaper &SymReaper;
132
133public:
134 MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
135
136 bool VisitSymbol(SymbolRef sym) override {
137 SymReaper.markLive(sym);
138 return true;
139 }
140
141 bool VisitMemRegion(const MemRegion *R) override {
142 SymReaper.markLive(R);
143 return true;
144 }
145};
146
147} // namespace
148
149// removeDeadBindings:
150// - Remove subexpression bindings.
151// - Remove dead block expression bindings.
152// - Keep live block expression bindings:
153// - Mark their reachable symbols live in SymbolReaper,
154// see ScanReachableSymbols.
155// - Mark the region in DRoots if the binding is a loc::MemRegionVal.
158 SymbolReaper &SymReaper,
159 ProgramStateRef ST) {
160 // We construct a new Environment object entirely, as this is cheaper than
161 // individually removing all the subexpression bindings (which will greatly
162 // outnumber block-level expression bindings).
164
165 MarkLiveCallback CB(SymReaper);
166 ScanReachableSymbols RSScaner(ST, CB);
167
168 llvm::ImmutableMapRef<EnvironmentEntry, SVal>
169 EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
170 F.getTreeFactory());
171
172 // Iterate over the block-expr bindings.
173 for (Environment::iterator I = Env.begin(), End = Env.end(); I != End; ++I) {
174 const EnvironmentEntry &BlkExpr = I.getKey();
175 SVal X = I.getData();
176
177 if (SymReaper.isLive(BlkExpr.getExpr(), BlkExpr.getStackFrame())) {
178 // Copy the binding to the new map.
179 EBMapRef = EBMapRef.add(BlkExpr, X);
180
181 // Mark all symbols in the block expr's value live.
182 RSScaner.scan(X);
183 }
184 }
185
186 NewEnv.ExprBindings = EBMapRef.asImmutableMap();
187 return NewEnv;
188}
189
190void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
191 const StackFrame *SF, const char *NL,
192 unsigned int Space, bool IsDot) const {
193 Indent(Out, Space, IsDot) << "\"environment\": ";
194
195 if (ExprBindings.isEmpty()) {
196 Out << "null," << NL;
197 return;
198 }
199
200 ++Space;
201 if (!SF) {
202 // Find the freshest stack frame.
204 for (const auto &I : *this) {
205 const StackFrame *CurrentSF = I.first.getStackFrame();
206 if (FoundStackFrames.count(CurrentSF) == 0) {
207 // This stack frame is fresher than all other stack frames so far.
208 SF = CurrentSF;
209 for (const StackFrame *SFI = CurrentSF; SFI; SFI = SFI->getParent())
210 FoundStackFrames.insert(SFI);
211 }
212 }
213 }
214
215 assert(SF);
216
217 Out << "{ \"pointer\": \"" << (const void *)SF << "\", \"items\": [" << NL;
219
220 SF->printJson(Out, NL, Space, IsDot, [&](const StackFrame *SF) {
221 // SF items begin
222 bool HasItem = false;
223 unsigned int InnerSpace = Space + 1;
224
225 // Store the last ExprBinding which we will print.
226 BindingsTy::iterator LastI = ExprBindings.end();
227 for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
228 ++I) {
229 if (I->first.getStackFrame() != SF)
230 continue;
231
232 if (!HasItem) {
233 HasItem = true;
234 Out << '[' << NL;
235 }
236
237 const Expr *Ex = I->first.getExpr();
238 (void)Ex;
239 assert(Ex != nullptr && "Expected non-null Expr");
240
241 LastI = I;
242 }
243
244 for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
245 ++I) {
246 if (I->first.getStackFrame() != SF)
247 continue;
248
249 const Expr *Ex = I->first.getExpr();
250 Indent(Out, InnerSpace, IsDot)
251 << "{ \"stmt_id\": " << Ex->getID(Ctx) << ", \"kind\": \""
252 << Ex->getStmtClassName() << "\", \"pretty\": ";
253 Ex->printJson(Out, nullptr, PP, /*AddQuotes=*/true);
254
255 Out << ", \"value\": ";
256 I->second.printJson(Out, /*AddQuotes=*/true);
257
258 Out << " }";
259
260 if (I != LastI)
261 Out << ',';
262 Out << NL;
263 }
264
265 if (HasItem)
266 Indent(Out, --InnerSpace, IsDot) << ']';
267 else
268 Out << "null ";
269 });
270
271 Indent(Out, --Space, IsDot) << "]}," << NL;
272}
#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:226
const clang::PrintingPolicy & getPrintingPolicy() const
Definition ASTContext.h:857
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:3093
It represents a stack frame of the call stack.
void printJson(raw_ostream &Out, const char *NL="\n", unsigned int Space=0, bool IsDot=false, std::function< void(const StackFrame *)> printMoreInfoPerStackFrame=[](const StackFrame *) {}) const
Prints out the call stack in json format.
const StackFrame * getParent() const
It might return null.
void printJson(raw_ostream &Out, PrinterHelper *Helper, const PrintingPolicy &Policy, bool AddQuotes) const
Pretty-prints in JSON format.
StmtClass getStmtClass() const
Definition Stmt.h:1503
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 StackFrame.
Definition Environment.h:35
const Expr * getExpr() const
Definition Environment.h:39
const StackFrame * getStackFrame() const
Definition Environment.h:40
EnvironmentEntry(const Expr *E, const StackFrame *SF)
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:55
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 StackFrame *SF=nullptr, const char *NL="\n", unsigned int Space=0, bool IsDot=false) const
iterator end() const
Definition Environment.h:71
iterator begin() const
Definition Environment.h:70
BindingsTy::iterator iterator
Definition Environment.h:68
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: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.
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.