Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 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"
20
#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.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
 
64
  std::string VisitUndefinedVal(UndefinedVal V) {
65
    return "undefined value";
66
  }
67
 
68
  std::string VisitLocMemRegionVal(loc::MemRegionVal V) {
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
 
79
  std::string VisitLocConcreteInt(loc::ConcreteInt V) {
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
 
87
  std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
88
    return Visit(V.getSymbol());
89
  }
90
 
91
  std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
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
 
100
  std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
101
    return "lazily frozen compound value of " + Visit(V.getRegion());
102
  }
103
 
104
  std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
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()
166
            .getCanonicalType()->getAs<ObjCObjectPointerType>())
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
 
178
  std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
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
 
206
  std::string VisitNonParamVarRegion(const NonParamVarRegion *R) {
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
 
233
  std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
234
    return "temporary object constructed at statement '" +
235
           printStmt(R->getExpr()) + "'";
236
  }
237
 
238
  std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
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