clang 22.0.0git
SValExplainer.h
Go to the documentation of this file.
1//== SValExplainer.h - Symbolic value explainer -----------------*- C++ -*--==//
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 defines SValExplainer, a class for pretty-printing a
10// human-readable description of a symbolic value. For example,
11// "reg_$0<x>" is turned into "initial value of variable 'x'".
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
16#define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
17
18#include "clang/AST/Attr.h"
19#include "clang/AST/DeclCXX.h"
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/Support/raw_ostream.h"
23
24namespace clang {
25
26namespace ento {
27
28class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
29private:
30 ASTContext &ACtx;
31 ProgramStateRef State;
32
33 std::string printCFGElementRef(ConstCFGElementRef Elem) {
34 std::string Str;
35 llvm::raw_string_ostream OS(Str);
36 Elem->dumpToStream(OS, /*TerminateWithNewLine=*/false);
37 return Str;
38 }
39
40 std::string printStmt(const Stmt *S) {
41 std::string Str;
42 llvm::raw_string_ostream OS(Str);
43 S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
44 return Str;
45 }
46
47 bool isThisObject(const SymbolicRegion *R) {
48 if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
49 if (isa<CXXThisRegion>(S->getRegion()))
50 return true;
51 return false;
52 }
53
54 bool isThisObject(const ElementRegion *R) {
55 if (const auto *Idx = R->getIndex().getAsInteger()) {
56 if (const auto *SR = R->getSuperRegion()->getAs<SymbolicRegion>()) {
57 QualType Ty = SR->getPointeeStaticType();
58 bool IsNotReinterpretCast = R->getValueType() == Ty;
59 if (Idx->isZero() && IsNotReinterpretCast)
60 return isThisObject(SR);
61 }
62 }
63 return false;
64 }
65
66public:
68 : ACtx(Ctx), State(State) {}
69
71 return "unknown value";
72 }
73
75 return "undefined value";
76 }
77
79 const MemRegion *R = V.getRegion();
80 // Avoid the weird "pointer to pointee of ...".
81 if (auto SR = dyn_cast<SymbolicRegion>(R)) {
82 // However, "pointer to 'this' object" is fine.
83 if (!isThisObject(SR))
84 return Visit(SR->getSymbol());
85 }
86 return "pointer to " + Visit(R);
87 }
88
90 const llvm::APSInt &I = V.getValue();
91 std::string Str;
92 llvm::raw_string_ostream OS(Str);
93 OS << "concrete memory address '" << I << "'";
94 return Str;
95 }
96
98 return Visit(V.getSymbol());
99 }
100
102 const llvm::APSInt &I = V.getValue();
103 std::string Str;
104 llvm::raw_string_ostream OS(Str);
105 OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
106 << "-bit integer '" << I << "'";
107 return Str;
108 }
109
111 return "lazily frozen compound value of " + Visit(V.getRegion());
112 }
113
115 const MemRegion *R = S->getRegion();
116 // Special handling for argument values.
117 if (auto V = dyn_cast<VarRegion>(R))
118 if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
119 return "argument '" + D->getQualifiedNameAsString() + "'";
120 return "initial value of " + Visit(R);
121 }
122
123 std::string VisitSymbolConjured(const SymbolConjured *S) {
124 return "symbol of type '" + S->getType().getAsString() +
125 "' conjured at CFG element '" +
126 printCFGElementRef(S->getCFGElementRef()) + "'";
127 }
128
129 std::string VisitSymbolDerived(const SymbolDerived *S) {
130 return "value derived from (" + Visit(S->getParentSymbol()) +
131 ") for " + Visit(S->getRegion());
132 }
133
134 std::string VisitSymbolExtent(const SymbolExtent *S) {
135 return "extent of " + Visit(S->getRegion());
136 }
137
138 std::string VisitSymbolMetadata(const SymbolMetadata *S) {
139 return "metadata of type '" + S->getType().getAsString() + "' tied to " +
140 Visit(S->getRegion());
141 }
142
143 std::string VisitSymIntExpr(const SymIntExpr *S) {
144 std::string Str;
145 llvm::raw_string_ostream OS(Str);
146 OS << "(" << Visit(S->getLHS()) << ") "
147 << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
148 << S->getRHS();
149 return Str;
150 }
151
152 // TODO: IntSymExpr doesn't appear in practice.
153 // Add the relevant code once it does.
154
155 std::string VisitSymSymExpr(const SymSymExpr *S) {
156 return "(" + Visit(S->getLHS()) + ") " +
157 std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
158 " (" + Visit(S->getRHS()) + ")";
159 }
160
161 std::string VisitUnarySymExpr(const UnarySymExpr *S) {
162 return std::string(UnaryOperator::getOpcodeStr(S->getOpcode())) + " (" +
163 Visit(S->getOperand()) + ")";
164 }
165
166 // TODO: SymbolCast doesn't appear in practice.
167 // Add the relevant code once it does.
168
169 std::string VisitSymbolicRegion(const SymbolicRegion *R) {
170 // Explain 'this' object here - if it's not wrapped by an ElementRegion.
171 // TODO: Explain CXXThisRegion itself, find a way to test it.
172 if (isThisObject(R))
173 return "'this' object";
174 // Objective-C objects are not normal symbolic regions. At least,
175 // they're always on the heap.
176 if (R->getSymbol()->getType()
178 return "object at " + Visit(R->getSymbol());
179 // Other heap-based symbolic regions are also special.
180 if (R->hasMemorySpace<HeapSpaceRegion>(State))
181 return "heap segment that starts at " + Visit(R->getSymbol());
182 return "pointee of " + Visit(R->getSymbol());
183 }
184
185 std::string VisitAllocaRegion(const AllocaRegion *R) {
186 return "region allocated by '" + printStmt(R->getExpr()) + "'";
187 }
188
190 return "compound literal " + printStmt(R->getLiteralExpr());
191 }
192
193 std::string VisitStringRegion(const StringRegion *R) {
194 return "string literal " + R->getString();
195 }
196
197 std::string VisitElementRegion(const ElementRegion *R) {
198 std::string Str;
199 llvm::raw_string_ostream OS(Str);
200
201 // Explain 'this' object here.
202 // They are represented by a SymRegion wrapped by an ElementRegion; so
203 // match and handle it here.
204 if (isThisObject(R))
205 return "'this' object";
206
207 OS << "element of type '" << R->getElementType() << "' with index ";
208 // For concrete index: omit type of the index integer.
209 if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
210 OS << I->getValue();
211 else
212 OS << "'" << Visit(R->getIndex()) << "'";
213 OS << " of " + Visit(R->getSuperRegion());
214 return Str;
215 }
216
218 const VarDecl *VD = R->getDecl();
219 std::string Name = VD->getQualifiedNameAsString();
220 if (isa<ParmVarDecl>(VD))
221 return "parameter '" + Name + "'";
222 else if (VD->hasAttr<BlocksAttr>())
223 return "block variable '" + Name + "'";
224 else if (VD->hasLocalStorage())
225 return "local variable '" + Name + "'";
226 else if (VD->isStaticLocal())
227 return "static local variable '" + Name + "'";
228 else if (VD->hasGlobalStorage())
229 return "global variable '" + Name + "'";
230 else
231 llvm_unreachable("A variable is either local or global");
232 }
233
234 std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) {
235 return "instance variable '" + R->getDecl()->getNameAsString() + "' of " +
236 Visit(R->getSuperRegion());
237 }
238
239 std::string VisitFieldRegion(const FieldRegion *R) {
240 return "field '" + R->getDecl()->getNameAsString() + "' of " +
241 Visit(R->getSuperRegion());
242 }
243
245 return "temporary object constructed at statement '" +
246 printStmt(R->getExpr()) + "'";
247 }
248
250 return "base object '" + R->getDecl()->getQualifiedNameAsString() +
251 "' inside " + Visit(R->getSuperRegion());
252 }
253
254 std::string VisitParamVarRegion(const ParamVarRegion *R) {
255 std::string Str;
256 llvm::raw_string_ostream OS(Str);
257
258 const ParmVarDecl *PVD = R->getDecl();
259 std::string Name = PVD->getQualifiedNameAsString();
260 if (!Name.empty()) {
261 OS << "parameter '" << Name << "'";
262 return std::string(OS.str());
263 }
264
265 unsigned Index = R->getIndex() + 1;
266 OS << Index << llvm::getOrdinalSuffix(Index) << " parameter of ";
267 const Decl *Parent = R->getStackFrame()->getDecl();
268 if (const auto *FD = dyn_cast<FunctionDecl>(Parent))
269 OS << "function '" << FD->getQualifiedNameAsString() << "()'";
270 else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent))
271 OS << "C++ constructor '" << CD->getQualifiedNameAsString() << "()'";
272 else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
273 if (MD->isClassMethod())
274 OS << "Objective-C method '+" << MD->getQualifiedNameAsString() << "'";
275 else
276 OS << "Objective-C method '-" << MD->getQualifiedNameAsString() << "'";
277 } else if (isa<BlockDecl>(Parent)) {
278 if (cast<BlockDecl>(Parent)->isConversionFromLambda())
279 OS << "lambda";
280 else
281 OS << "block";
282 }
283
284 return std::string(OS.str());
285 }
286
287 std::string VisitSVal(SVal V) {
288 std::string Str;
289 llvm::raw_string_ostream OS(Str);
290 OS << V;
291 return "a value unsupported by the explainer: (" +
292 std::string(OS.str()) + ")";
293 }
294
295 std::string VisitSymExpr(SymbolRef S) {
296 std::string Str;
297 llvm::raw_string_ostream OS(Str);
298 S->dumpToStream(OS);
299 return "a symbolic expression unsupported by the explainer: (" +
300 std::string(OS.str()) + ")";
301 }
302
303 std::string VisitMemRegion(const MemRegion *R) {
304 std::string Str;
305 llvm::raw_string_ostream OS(Str);
306 OS << R;
307 return "a memory region unsupported by the explainer (" +
308 std::string(OS.str()) + ")";
309 }
310};
311
312} // end namespace ento
313
314} // end namespace clang
315
316#endif
#define V(N, I)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:188
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Definition Expr.cpp:2128
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool hasAttr() const
Definition DeclBase.h:577
const Decl * getDecl() const
std::string getQualifiedNameAsString() const
Definition Decl.cpp:1680
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Definition Decl.h:316
Represents a pointer to an Objective C object.
Definition TypeBase.h:7903
Represents a parameter to a function.
Definition Decl.h:1789
A (possibly-)qualified type.
Definition TypeBase.h:937
QualType getCanonicalType() const
Definition TypeBase.h:8337
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition TypeBase.h:1332
Stmt - This represents one statement.
Definition Stmt.h:85
void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation=0, StringRef NewlineSymbol="\n", const ASTContext *Context=nullptr) const
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9098
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Definition Expr.cpp:1402
Represents a variable declaration or definition.
Definition Decl.h:925
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition Decl.h:1225
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Definition Decl.h:1207
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition Decl.h:1183
AllocaRegion - A region that represents an untyped blob of bytes created by a call to 'alloca'.
Definition MemRegion.h:506
LLVM_ATTRIBUTE_RETURNS_NONNULL const Expr * getExpr() const
Definition MemRegion.h:525
BinaryOperator::Opcode getOpcode() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const CXXRecordDecl * getDecl() const
Definition MemRegion.h:1355
LLVM_ATTRIBUTE_RETURNS_NONNULL const Expr * getExpr() const
Definition MemRegion.h:1282
CompoundLiteralRegion - A memory region representing a compound literal.
Definition MemRegion.h:928
LLVM_ATTRIBUTE_RETURNS_NONNULL const CompoundLiteralExpr * getLiteralExpr() const
Definition MemRegion.h:955
ElementRegion is used to represent both array elements and casts.
Definition MemRegion.h:1227
QualType getValueType() const override
Definition MemRegion.h:1249
QualType getElementType() const
Definition MemRegion.h:1251
LLVM_ATTRIBUTE_RETURNS_NONNULL const FieldDecl * getDecl() const override
Definition MemRegion.h:1153
FullSValVisitor - a convenient mixed visitor for all three: SVal, SymExpr and MemRegion subclasses.
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:98
bool hasMemorySpace(ProgramStateRef State) const
Definition MemRegion.h:148
std::string getString() const
Get a string representation of a region for debug use.
const RegionTy * getAs() const
Definition MemRegion.h:1416
LLVM_ATTRIBUTE_RETURNS_NONNULL const VarDecl * getDecl() const override
Definition MemRegion.h:1034
LLVM_ATTRIBUTE_RETURNS_NONNULL const ObjCIvarDecl * getDecl() const override
ParamVarRegion - Represents a region for parameters.
Definition MemRegion.h:1062
const ParmVarDecl * getDecl() const override
TODO: What does this return?
unsigned getIndex() const
Definition MemRegion.h:1080
std::string VisitSymbolRegionValue(const SymbolRegionValue *S)
std::string VisitFieldRegion(const FieldRegion *R)
std::string VisitConcreteInt(nonloc::ConcreteInt V)
std::string VisitSVal(SVal V)
std::string VisitObjCIvarRegion(const ObjCIvarRegion *R)
std::string VisitParamVarRegion(const ParamVarRegion *R)
std::string VisitSymbolDerived(const SymbolDerived *S)
std::string VisitUnarySymExpr(const UnarySymExpr *S)
std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R)
std::string VisitSymIntExpr(const SymIntExpr *S)
std::string VisitSymExpr(SymbolRef S)
std::string VisitSymbolicRegion(const SymbolicRegion *R)
std::string VisitSymbolVal(nonloc::SymbolVal V)
std::string VisitMemRegion(const MemRegion *R)
SValExplainer(ASTContext &Ctx, ProgramStateRef State)
std::string VisitUnknownVal(UnknownVal V)
std::string VisitConcreteInt(loc::ConcreteInt V)
std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R)
std::string VisitNonParamVarRegion(const NonParamVarRegion *R)
std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R)
std::string VisitSymbolMetadata(const SymbolMetadata *S)
std::string VisitSymSymExpr(const SymSymExpr *S)
std::string VisitSymbolConjured(const SymbolConjured *S)
std::string VisitSymbolExtent(const SymbolExtent *S)
std::string VisitUndefinedVal(UndefinedVal V)
std::string VisitAllocaRegion(const AllocaRegion *R)
std::string VisitElementRegion(const ElementRegion *R)
std::string VisitMemRegionVal(loc::MemRegionVal V)
std::string VisitLazyCompoundVal(nonloc::LazyCompoundVal V)
std::string VisitStringRegion(const StringRegion *R)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:87
const llvm::APSInt * getAsInteger() const
If this SVal is loc::ConcreteInt or nonloc::ConcreteInt, return a pointer to APSInt which is held in ...
Definition SVals.cpp:111
StringRegion - Region associated with a StringLiteral.
Definition MemRegion.h:857
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
Definition MemRegion.h:487
virtual void dumpToStream(raw_ostream &os) const
Definition SymExpr.h:81
virtual QualType getType() const =0
A symbol representing the result of an expression in the case when we do not know anything about what...
ConstCFGElementRef getCFGElementRef() const
QualType getType() const override
A symbol representing the value of a MemRegion whose parent region has symbolic value.
LLVM_ATTRIBUTE_RETURNS_NONNULL SymbolRef getParentSymbol() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const
SymbolExtent - Represents the extent (size in bytes) of a bounded region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const SubRegion * getRegion() const
SymbolMetadata - Represents path-dependent metadata about a specific region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getRegion() const
QualType getType() const override
A symbol representing the value stored at a MemRegion.
LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const
SymbolicRegion - A special, "non-concrete" region.
Definition MemRegion.h:808
SymbolRef getSymbol() const
It might return null.
Definition MemRegion.h:827
Represents a symbolic expression involving a unary operator.
UnaryOperator::Opcode getOpcode() const
const SymExpr * getOperand() const
const StackFrameContext * getStackFrame() const
It might return null.
Value representing integer constant.
Definition SVals.h:300
While nonloc::CompoundVal covers a few simple use cases, nonloc::LazyCompoundVal is a more performant...
Definition SVals.h:389
Represents symbolic expression that isn't a location.
Definition SVals.h:279
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
BinarySymExprImpl< const SymExpr *, const SymExpr *, SymExpr::Kind::SymSymExprKind > SymSymExpr
Represents a symbolic expression like 'x' + 'y'.
BinarySymExprImpl< const SymExpr *, APSIntPtr, SymExpr::Kind::SymIntExprKind > SymIntExpr
Represents a symbolic expression like 'x' + 3.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
CFGBlock::ConstCFGElementRef ConstCFGElementRef
Definition CFG.h:1199
U cast(CodeGen::Address addr)
Definition Address.h:327
Describes how types, statements, expressions, and declarations should be printed.