Clang Project

clang_source_code/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
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/DeclCXX.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
20
21namespace clang {
22
23namespace ento {
24
25class SValExplainer : public FullSValVisitor<SValExplainerstd::string> {
26private:
27  ASTContext &ACtx;
28
29  std::string printStmt(const Stmt *S) {
30    std::string Str;
31    llvm::raw_string_ostream OS(Str);
32    S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
33    return OS.str();
34  }
35
36  bool isThisObject(const SymbolicRegion *R) {
37    if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
38      if (isa<CXXThisRegion>(S->getRegion()))
39        return true;
40    return false;
41  }
42
43public:
44  SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
45
46  std::string VisitUnknownVal(UnknownVal V) {
47    return "unknown value";
48  }
49
50  std::string VisitUndefinedVal(UndefinedVal V) {
51    return "undefined value";
52  }
53
54  std::string VisitLocMemRegionVal(loc::MemRegionVal V) {
55    const MemRegion *R = V.getRegion();
56    // Avoid the weird "pointer to pointee of ...".
57    if (auto SR = dyn_cast<SymbolicRegion>(R)) {
58      // However, "pointer to 'this' object" is fine.
59      if (!isThisObject(SR))
60        return Visit(SR->getSymbol());
61    }
62    return "pointer to " + Visit(R);
63  }
64
65  std::string VisitLocConcreteInt(loc::ConcreteInt V) {
66    llvm::APSInt I = V.getValue();
67    std::string Str;
68    llvm::raw_string_ostream OS(Str);
69    OS << "concrete memory address '" << I << "'";
70    return OS.str();
71  }
72
73  std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
74    return Visit(V.getSymbol());
75  }
76
77  std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
78    llvm::APSInt I = V.getValue();
79    std::string Str;
80    llvm::raw_string_ostream OS(Str);
81    OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
82       << "-bit integer '" << I << "'";
83    return OS.str();
84  }
85
86  std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
87    return "lazily frozen compound value of " + Visit(V.getRegion());
88  }
89
90  std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
91    const MemRegion *R = S->getRegion();
92    // Special handling for argument values.
93    if (auto V = dyn_cast<VarRegion>(R))
94      if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
95        return "argument '" + D->getQualifiedNameAsString() + "'";
96    return "initial value of " + Visit(R);
97  }
98
99  std::string VisitSymbolConjured(const SymbolConjured *S) {
100    return "symbol of type '" + S->getType().getAsString() +
101           "' conjured at statement '" + printStmt(S->getStmt()) + "'";
102  }
103
104  std::string VisitSymbolDerived(const SymbolDerived *S) {
105    return "value derived from (" + Visit(S->getParentSymbol()) +
106           ") for " + Visit(S->getRegion());
107  }
108
109  std::string VisitSymbolExtent(const SymbolExtent *S) {
110    return "extent of " + Visit(S->getRegion());
111  }
112
113  std::string VisitSymbolMetadata(const SymbolMetadata *S) {
114    return "metadata of type '" + S->getType().getAsString() + "' tied to " +
115           Visit(S->getRegion());
116  }
117
118  std::string VisitSymIntExpr(const SymIntExpr *S) {
119    std::string Str;
120    llvm::raw_string_ostream OS(Str);
121    OS << "(" << Visit(S->getLHS()) << ") "
122       << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
123       << S->getRHS();
124    return OS.str();
125  }
126
127  // TODO: IntSymExpr doesn't appear in practice.
128  // Add the relevant code once it does.
129
130  std::string VisitSymSymExpr(const SymSymExpr *S) {
131    return "(" + Visit(S->getLHS()) + ") " +
132           std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
133           " (" + Visit(S->getRHS()) + ")";
134  }
135
136  // TODO: SymbolCast doesn't appear in practice.
137  // Add the relevant code once it does.
138
139  std::string VisitSymbolicRegion(const SymbolicRegion *R) {
140    // Explain 'this' object here.
141    // TODO: Explain CXXThisRegion itself, find a way to test it.
142    if (isThisObject(R))
143      return "'this' object";
144    // Objective-C objects are not normal symbolic regions. At least,
145    // they're always on the heap.
146    if (R->getSymbol()->getType()
147            .getCanonicalType()->getAs<ObjCObjectPointerType>())
148      return "object at " + Visit(R->getSymbol());
149    // Other heap-based symbolic regions are also special.
150    if (isa<HeapSpaceRegion>(R->getMemorySpace()))
151      return "heap segment that starts at " + Visit(R->getSymbol());
152    return "pointee of " + Visit(R->getSymbol());
153  }
154
155  std::string VisitAllocaRegion(const AllocaRegion *R) {
156    return "region allocated by '" + printStmt(R->getExpr()) + "'";
157  }
158
159  std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
160    return "compound literal " + printStmt(R->getLiteralExpr());
161  }
162
163  std::string VisitStringRegion(const StringRegion *R) {
164    return "string literal " + R->getString();
165  }
166
167  std::string VisitElementRegion(const ElementRegion *R) {
168    std::string Str;
169    llvm::raw_string_ostream OS(Str);
170    OS << "element of type '" << R->getElementType().getAsString()
171       << "' with index ";
172    // For concrete index: omit type of the index integer.
173    if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
174      OS << I->getValue();
175    else
176      OS << "'" << Visit(R->getIndex()) << "'";
177    OS << " of " + Visit(R->getSuperRegion());
178    return OS.str();
179  }
180
181  std::string VisitVarRegion(const VarRegion *R) {
182    const VarDecl *VD = R->getDecl();
183    std::string Name = VD->getQualifiedNameAsString();
184    if (isa<ParmVarDecl>(VD))
185      return "parameter '" + Name + "'";
186    else if (VD->hasAttr<BlocksAttr>())
187      return "block variable '" + Name + "'";
188    else if (VD->hasLocalStorage())
189      return "local variable '" + Name + "'";
190    else if (VD->isStaticLocal())
191      return "static local variable '" + Name + "'";
192    else if (VD->hasGlobalStorage())
193      return "global variable '" + Name + "'";
194    else
195      llvm_unreachable("A variable is either local or global");
196  }
197
198  std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) {
199    return "instance variable '" + R->getDecl()->getNameAsString() + "' of " +
200           Visit(R->getSuperRegion());
201  }
202
203  std::string VisitFieldRegion(const FieldRegion *R) {
204    return "field '" + R->getDecl()->getNameAsString() + "' of " +
205           Visit(R->getSuperRegion());
206  }
207
208  std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
209    return "temporary object constructed at statement '" +
210           printStmt(R->getExpr()) + "'";
211  }
212
213  std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
214    return "base object '" + R->getDecl()->getQualifiedNameAsString() +
215           "' inside " + Visit(R->getSuperRegion());
216  }
217
218  std::string VisitSVal(SVal V) {
219    std::string Str;
220    llvm::raw_string_ostream OS(Str);
221    OS << V;
222    return "a value unsupported by the explainer: (" +
223           std::string(OS.str()) + ")";
224  }
225
226  std::string VisitSymExpr(SymbolRef S) {
227    std::string Str;
228    llvm::raw_string_ostream OS(Str);
229    S->dumpToStream(OS);
230    return "a symbolic expression unsupported by the explainer: (" +
231           std::string(OS.str()) + ")";
232  }
233
234  std::string VisitMemRegion(const MemRegion *R) {
235    std::string Str;
236    llvm::raw_string_ostream OS(Str);
237    OS << R;
238    return "a memory region unsupported by the explainer (" +
239           std::string(OS.str()) + ")";
240  }
241};
242
243// end namespace ento
244
245// end namespace clang
246
247#endif
248
clang::ento::SValExplainer::ACtx
clang::ento::SValExplainer::printStmt
clang::ento::SValExplainer::isThisObject
clang::ento::SValExplainer::VisitUnknownVal
clang::ento::SValExplainer::VisitUndefinedVal
clang::ento::SValExplainer::VisitLocMemRegionVal
clang::ento::SValExplainer::VisitLocConcreteInt
clang::ento::SValExplainer::VisitNonLocSymbolVal
clang::ento::SValExplainer::VisitNonLocConcreteInt
clang::ento::SValExplainer::VisitNonLocLazyCompoundVal
clang::ento::SValExplainer::VisitSymbolRegionValue
clang::ento::SValExplainer::VisitSymbolConjured
clang::ento::SValExplainer::VisitSymbolDerived
clang::ento::SValExplainer::VisitSymbolExtent
clang::ento::SValExplainer::VisitSymbolMetadata
clang::ento::SValExplainer::VisitSymIntExpr
clang::ento::SValExplainer::VisitSymSymExpr
clang::ento::SValExplainer::VisitSymbolicRegion
clang::ento::SValExplainer::VisitAllocaRegion
clang::ento::SValExplainer::VisitCompoundLiteralRegion
clang::ento::SValExplainer::VisitStringRegion
clang::ento::SValExplainer::VisitElementRegion
clang::ento::SValExplainer::VisitVarRegion
clang::ento::SValExplainer::VisitObjCIvarRegion
clang::ento::SValExplainer::VisitFieldRegion
clang::ento::SValExplainer::VisitCXXTempObjectRegion
clang::ento::SValExplainer::VisitCXXBaseObjectRegion
clang::ento::SValExplainer::VisitSVal
clang::ento::SValExplainer::VisitSymExpr
clang::ento::SValExplainer::VisitMemRegion