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