1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
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 | |
21 | namespace clang { |
22 | |
23 | namespace ento { |
24 | |
25 | class SValExplainer : public FullSValVisitor<SValExplainer, std::string> { |
26 | private: |
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 | |
43 | public: |
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 | |
57 | if (auto SR = dyn_cast<SymbolicRegion>(R)) { |
58 | |
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 | |
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 | |
128 | |
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 | |
137 | |
138 | |
139 | std::string VisitSymbolicRegion(const SymbolicRegion *R) { |
140 | |
141 | |
142 | if (isThisObject(R)) |
143 | return "'this' object"; |
144 | |
145 | |
146 | if (R->getSymbol()->getType() |
147 | .getCanonicalType()->getAs<ObjCObjectPointerType>()) |
148 | return "object at " + Visit(R->getSymbol()); |
149 | |
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 | |
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 | } |
244 | |
245 | } |
246 | |
247 | #endif |
248 | |