Coverage Report

Created: 2020-11-24 06:42

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