clang  19.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 
23 namespace clang {
24 
25 namespace ento {
26 
27 class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
28 private:
29  ASTContext &ACtx;
30 
31  std::string printStmt(const Stmt *S) {
32  std::string Str;
33  llvm::raw_string_ostream OS(Str);
34  S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
35  return Str;
36  }
37 
38  bool isThisObject(const SymbolicRegion *R) {
39  if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
40  if (isa<CXXThisRegion>(S->getRegion()))
41  return true;
42  return false;
43  }
44 
45  bool isThisObject(const ElementRegion *R) {
46  if (const auto *Idx = R->getIndex().getAsInteger()) {
47  if (const auto *SR = R->getSuperRegion()->getAs<SymbolicRegion>()) {
48  QualType Ty = SR->getPointeeStaticType();
49  bool IsNotReinterpretCast = R->getValueType() == Ty;
50  if (Idx->isZero() && IsNotReinterpretCast)
51  return isThisObject(SR);
52  }
53  }
54  return false;
55  }
56 
57 public:
58  SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
59 
60  std::string VisitUnknownVal(UnknownVal V) {
61  return "unknown value";
62  }
63 
65  return "undefined value";
66  }
67 
69  const MemRegion *R = V.getRegion();
70  // Avoid the weird "pointer to pointee of ...".
71  if (auto SR = dyn_cast<SymbolicRegion>(R)) {
72  // However, "pointer to 'this' object" is fine.
73  if (!isThisObject(SR))
74  return Visit(SR->getSymbol());
75  }
76  return "pointer to " + Visit(R);
77  }
78 
80  const llvm::APSInt &I = V.getValue();
81  std::string Str;
82  llvm::raw_string_ostream OS(Str);
83  OS << "concrete memory address '" << I << "'";
84  return Str;
85  }
86 
88  return Visit(V.getSymbol());
89  }
90 
92  const llvm::APSInt &I = V.getValue();
93  std::string Str;
94  llvm::raw_string_ostream OS(Str);
95  OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
96  << "-bit integer '" << I << "'";
97  return Str;
98  }
99 
101  return "lazily frozen compound value of " + Visit(V.getRegion());
102  }
103 
105  const MemRegion *R = S->getRegion();
106  // Special handling for argument values.
107  if (auto V = dyn_cast<VarRegion>(R))
108  if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
109  return "argument '" + D->getQualifiedNameAsString() + "'";
110  return "initial value of " + Visit(R);
111  }
112 
113  std::string VisitSymbolConjured(const SymbolConjured *S) {
114  return "symbol of type '" + S->getType().getAsString() +
115  "' conjured at statement '" + printStmt(S->getStmt()) + "'";
116  }
117 
118  std::string VisitSymbolDerived(const SymbolDerived *S) {
119  return "value derived from (" + Visit(S->getParentSymbol()) +
120  ") for " + Visit(S->getRegion());
121  }
122 
123  std::string VisitSymbolExtent(const SymbolExtent *S) {
124  return "extent of " + Visit(S->getRegion());
125  }
126 
127  std::string VisitSymbolMetadata(const SymbolMetadata *S) {
128  return "metadata of type '" + S->getType().getAsString() + "' tied to " +
129  Visit(S->getRegion());
130  }
131 
132  std::string VisitSymIntExpr(const SymIntExpr *S) {
133  std::string Str;
134  llvm::raw_string_ostream OS(Str);
135  OS << "(" << Visit(S->getLHS()) << ") "
136  << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
137  << S->getRHS();
138  return Str;
139  }
140 
141  // TODO: IntSymExpr doesn't appear in practice.
142  // Add the relevant code once it does.
143 
144  std::string VisitSymSymExpr(const SymSymExpr *S) {
145  return "(" + Visit(S->getLHS()) + ") " +
146  std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
147  " (" + Visit(S->getRHS()) + ")";
148  }
149 
150  std::string VisitUnarySymExpr(const UnarySymExpr *S) {
151  return std::string(UnaryOperator::getOpcodeStr(S->getOpcode())) + " (" +
152  Visit(S->getOperand()) + ")";
153  }
154 
155  // TODO: SymbolCast doesn't appear in practice.
156  // Add the relevant code once it does.
157 
158  std::string VisitSymbolicRegion(const SymbolicRegion *R) {
159  // Explain 'this' object here - if it's not wrapped by an ElementRegion.
160  // TODO: Explain CXXThisRegion itself, find a way to test it.
161  if (isThisObject(R))
162  return "'this' object";
163  // Objective-C objects are not normal symbolic regions. At least,
164  // they're always on the heap.
165  if (R->getSymbol()->getType()
167  return "object at " + Visit(R->getSymbol());
168  // Other heap-based symbolic regions are also special.
169  if (isa<HeapSpaceRegion>(R->getMemorySpace()))
170  return "heap segment that starts at " + Visit(R->getSymbol());
171  return "pointee of " + Visit(R->getSymbol());
172  }
173 
174  std::string VisitAllocaRegion(const AllocaRegion *R) {
175  return "region allocated by '" + printStmt(R->getExpr()) + "'";
176  }
177 
179  return "compound literal " + printStmt(R->getLiteralExpr());
180  }
181 
182  std::string VisitStringRegion(const StringRegion *R) {
183  return "string literal " + R->getString();
184  }
185 
186  std::string VisitElementRegion(const ElementRegion *R) {
187  std::string Str;
188  llvm::raw_string_ostream OS(Str);
189 
190  // Explain 'this' object here.
191  // They are represented by a SymRegion wrapped by an ElementRegion; so
192  // match and handle it here.
193  if (isThisObject(R))
194  return "'this' object";
195 
196  OS << "element of type '" << R->getElementType() << "' with index ";
197  // For concrete index: omit type of the index integer.
198  if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
199  OS << I->getValue();
200  else
201  OS << "'" << Visit(R->getIndex()) << "'";
202  OS << " of " + Visit(R->getSuperRegion());
203  return Str;
204  }
205 
207  const VarDecl *VD = R->getDecl();
208  std::string Name = VD->getQualifiedNameAsString();
209  if (isa<ParmVarDecl>(VD))
210  return "parameter '" + Name + "'";
211  else if (VD->hasAttr<BlocksAttr>())
212  return "block variable '" + Name + "'";
213  else if (VD->hasLocalStorage())
214  return "local variable '" + Name + "'";
215  else if (VD->isStaticLocal())
216  return "static local variable '" + Name + "'";
217  else if (VD->hasGlobalStorage())
218  return "global variable '" + Name + "'";
219  else
220  llvm_unreachable("A variable is either local or global");
221  }
222 
223  std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) {
224  return "instance variable '" + R->getDecl()->getNameAsString() + "' of " +
225  Visit(R->getSuperRegion());
226  }
227 
228  std::string VisitFieldRegion(const FieldRegion *R) {
229  return "field '" + R->getDecl()->getNameAsString() + "' of " +
230  Visit(R->getSuperRegion());
231  }
232 
234  return "temporary object constructed at statement '" +
235  printStmt(R->getExpr()) + "'";
236  }
237 
239  return "base object '" + R->getDecl()->getQualifiedNameAsString() +
240  "' inside " + Visit(R->getSuperRegion());
241  }
242 
243  std::string VisitParamVarRegion(const ParamVarRegion *R) {
244  std::string Str;
245  llvm::raw_string_ostream OS(Str);
246 
247  const ParmVarDecl *PVD = R->getDecl();
248  std::string Name = PVD->getQualifiedNameAsString();
249  if (!Name.empty()) {
250  OS << "parameter '" << Name << "'";
251  return std::string(OS.str());
252  }
253 
254  unsigned Index = R->getIndex() + 1;
255  OS << Index << llvm::getOrdinalSuffix(Index) << " parameter of ";
256  const Decl *Parent = R->getStackFrame()->getDecl();
257  if (const auto *FD = dyn_cast<FunctionDecl>(Parent))
258  OS << "function '" << FD->getQualifiedNameAsString() << "()'";
259  else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent))
260  OS << "C++ constructor '" << CD->getQualifiedNameAsString() << "()'";
261  else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
262  if (MD->isClassMethod())
263  OS << "Objective-C method '+" << MD->getQualifiedNameAsString() << "'";
264  else
265  OS << "Objective-C method '-" << MD->getQualifiedNameAsString() << "'";
266  } else if (isa<BlockDecl>(Parent)) {
267  if (cast<BlockDecl>(Parent)->isConversionFromLambda())
268  OS << "lambda";
269  else
270  OS << "block";
271  }
272 
273  return std::string(OS.str());
274  }
275 
276  std::string VisitSVal(SVal V) {
277  std::string Str;
278  llvm::raw_string_ostream OS(Str);
279  OS << V;
280  return "a value unsupported by the explainer: (" +
281  std::string(OS.str()) + ")";
282  }
283 
284  std::string VisitSymExpr(SymbolRef S) {
285  std::string Str;
286  llvm::raw_string_ostream OS(Str);
287  S->dumpToStream(OS);
288  return "a symbolic expression unsupported by the explainer: (" +
289  std::string(OS.str()) + ")";
290  }
291 
292  std::string VisitMemRegion(const MemRegion *R) {
293  std::string Str;
294  llvm::raw_string_ostream OS(Str);
295  OS << R;
296  return "a memory region unsupported by the explainer (" +
297  std::string(OS.str()) + ")";
298  }
299 };
300 
301 } // end namespace ento
302 
303 } // end namespace clang
304 
305 #endif
#define V(N, I)
Definition: ASTContext.h:3299
NodeId Parent
Definition: ASTDiff.cpp:191
llvm::APSInt APSInt
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:185
const LangOptions & getLangOpts() const
Definition: ASTContext.h:778
StringRef getOpcodeStr() const
Definition: Expr.h:3957
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
bool hasAttr() const
Definition: DeclBase.h:583
const Decl * getDecl() const
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:292
std::string getQualifiedNameAsString(bool WithGlobalNsPrefix=false) const
Definition: Decl.cpp:1683
Represents a pointer to an Objective C object.
Definition: Type.h:7020
Represents a parameter to a function.
Definition: Decl.h:1762
A (possibly-)qualified type.
Definition: Type.h:940
QualType getCanonicalType() const
Definition: Type.h:7423
Stmt - This represents one statement.
Definition: Stmt.h:84
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8160
static StringRef getOpcodeStr(Opcode Op)
getOpcodeStr - Turn an Opcode enum value into the punctuation char it corresponds to,...
Definition: Expr.cpp:1460
Represents a variable declaration or definition.
Definition: Decl.h:919
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition: Decl.h:1214
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Definition: Decl.h:1196
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition: Decl.h:1172
AllocaRegion - A region that represents an untyped blob of bytes created by a call to 'alloca'.
Definition: MemRegion.h:473
LLVM_ATTRIBUTE_RETURNS_NONNULL const Expr * getExpr() const
Definition: MemRegion.h:492
Template implementation for all binary symbolic expressions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const CXXRecordDecl * getDecl() const
Definition: MemRegion.h:1322
LLVM_ATTRIBUTE_RETURNS_NONNULL const Expr * getExpr() const
Definition: MemRegion.h:1249
CompoundLiteralRegion - A memory region representing a compound literal.
Definition: MemRegion.h:895
LLVM_ATTRIBUTE_RETURNS_NONNULL const CompoundLiteralExpr * getLiteralExpr() const
Definition: MemRegion.h:922
ElementRegion is used to represent both array elements and casts.
Definition: MemRegion.h:1194
QualType getValueType() const override
Definition: MemRegion.h:1216
QualType getElementType() const
Definition: MemRegion.h:1218
NonLoc getIndex() const
Definition: MemRegion.h:1214
LLVM_ATTRIBUTE_RETURNS_NONNULL const FieldDecl * getDecl() const override
Definition: MemRegion.h:1120
FullSValVisitor - a convenient mixed visitor for all three: SVal, SymExpr and MemRegion subclasses.
Definition: SValVisitor.h:130
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:96
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
Definition: MemRegion.cpp:1317
std::string getString() const
Get a string representation of a region for debug use.
Definition: MemRegion.cpp:469
const RegionTy * getAs() const
Definition: MemRegion.h:1383
LLVM_ATTRIBUTE_RETURNS_NONNULL const VarDecl * getDecl() const override
Definition: MemRegion.h:1001
LLVM_ATTRIBUTE_RETURNS_NONNULL const ObjCIvarDecl * getDecl() const override
Definition: MemRegion.cpp:179
ParamVarRegion - Represents a region for paremters.
Definition: MemRegion.h:1029
const ParmVarDecl * getDecl() const override
TODO: What does this return?
Definition: MemRegion.cpp:200
unsigned getIndex() const
Definition: MemRegion.h:1047
std::string VisitSymbolRegionValue(const SymbolRegionValue *S)
std::string VisitFieldRegion(const FieldRegion *R)
std::string VisitConcreteInt(nonloc::ConcreteInt V)
Definition: SValExplainer.h:91
std::string VisitSVal(SVal V)
std::string VisitObjCIvarRegion(const ObjCIvarRegion *R)
std::string VisitParamVarRegion(const ParamVarRegion *R)
std::string VisitSymbolDerived(const SymbolDerived *S)
SValExplainer(ASTContext &Ctx)
Definition: SValExplainer.h:58
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)
Definition: SValExplainer.h:87
std::string VisitMemRegion(const MemRegion *R)
std::string VisitUnknownVal(UnknownVal V)
Definition: SValExplainer.h:60
std::string VisitConcreteInt(loc::ConcreteInt V)
Definition: SValExplainer.h:79
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)
Definition: SValExplainer.h:64
std::string VisitAllocaRegion(const AllocaRegion *R)
std::string VisitElementRegion(const ElementRegion *R)
std::string VisitMemRegionVal(loc::MemRegionVal V)
Definition: SValExplainer.h:68
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:55
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:112
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:86
StringRegion - Region associated with a StringLiteral.
Definition: MemRegion.h:824
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
Definition: MemRegion.h:454
Symbolic value.
Definition: SymExpr.h:30
virtual QualType getType() const =0
A symbol representing the result of an expression in the case when we do not know anything about what...
Definition: SymbolManager.h:79
A symbol representing the value of a MemRegion whose parent region has symbolic value.
SymbolExtent - Represents the extent (size in bytes) of a bounded region.
SymbolMetadata - Represents path-dependent metadata about a specific region.
A symbol representing the value stored at a MemRegion.
Definition: SymbolManager.h:42
SymbolicRegion - A special, "non-concrete" region.
Definition: MemRegion.h:775
SymbolRef getSymbol() const
It might return null.
Definition: MemRegion.h:794
Represents a symbolic expression involving a unary operator.
const StackFrameContext * getStackFrame() const
It might return null.
Definition: MemRegion.cpp:157
Value representing integer constant.
Definition: SVals.h:297
Represents symbolic expression that isn't a location.
Definition: SVals.h:276
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