Coverage Report

Created: 2019-07-24 05:18

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