Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- Environment.cpp - Map from Stmt* to Locations/Values ---------------===//
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 defined the Environment and EnvironmentManager classes.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
14
#include "clang/AST/Expr.h"
15
#include "clang/AST/ExprCXX.h"
16
#include "clang/AST/PrettyPrinter.h"
17
#include "clang/AST/Stmt.h"
18
#include "clang/Analysis/AnalysisDeclContext.h"
19
#include "clang/Basic/LLVM.h"
20
#include "clang/Basic/LangOptions.h"
21
#include "clang/Basic/JsonSupport.h"
22
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
23
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
24
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
25
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
26
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
27
#include "llvm/ADT/ImmutableMap.h"
28
#include "llvm/ADT/SmallPtrSet.h"
29
#include "llvm/Support/Casting.h"
30
#include "llvm/Support/ErrorHandling.h"
31
#include "llvm/Support/raw_ostream.h"
32
#include <cassert>
33
34
using namespace clang;
35
using namespace ento;
36
37
3.49M
static const Expr *ignoreTransparentExprs(const Expr *E) {
38
3.49M
  E = E->IgnoreParens();
39
3.49M
40
3.49M
  switch (E->getStmtClass()) {
41
3.49M
  case Stmt::OpaqueValueExprClass:
42
3.00k
    E = cast<OpaqueValueExpr>(E)->getSourceExpr();
43
3.00k
    break;
44
3.49M
  case Stmt::ExprWithCleanupsClass:
45
4.41k
    E = cast<ExprWithCleanups>(E)->getSubExpr();
46
4.41k
    break;
47
3.49M
  case Stmt::ConstantExprClass:
48
0
    E = cast<ConstantExpr>(E)->getSubExpr();
49
0
    break;
50
3.49M
  case Stmt::CXXBindTemporaryExprClass:
51
996
    E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
52
996
    break;
53
3.49M
  case Stmt::SubstNonTypeTemplateParmExprClass:
54
14
    E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
55
14
    break;
56
3.49M
  default:
57
3.48M
    // This is the base case: we can't look through more than we already have.
58
3.48M
    return E;
59
8.43k
  }
60
8.43k
61
8.43k
  return ignoreTransparentExprs(E);
62
8.43k
}
63
64
3.50M
static const Stmt *ignoreTransparentExprs(const Stmt *S) {
65
3.50M
  if (const auto *E = dyn_cast<Expr>(S))
66
3.48M
    return ignoreTransparentExprs(E);
67
18.8k
  return S;
68
18.8k
}
69
70
EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L)
71
    : std::pair<const Stmt *,
72
                const StackFrameContext *>(ignoreTransparentExprs(S),
73
                                           L ? L->getStackFrame()
74
3.50M
                                             : nullptr) {}
75
76
1.32M
SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
77
1.32M
  const SVal* X = ExprBindings.lookup(E);
78
1.32M
  if (X) {
79
1.26M
    SVal V = *X;
80
1.26M
    return V;
81
1.26M
  }
82
61.3k
  return UnknownVal();
83
61.3k
}
84
85
SVal Environment::getSVal(const EnvironmentEntry &Entry,
86
1.41M
                          SValBuilder& svalBuilder) const {
87
1.41M
  const Stmt *S = Entry.getStmt();
88
1.41M
  const LocationContext *LCtx = Entry.getLocationContext();
89
1.41M
90
1.41M
  switch (S->getStmtClass()) {
91
1.41M
  case Stmt::CXXBindTemporaryExprClass:
92
0
  case Stmt::ExprWithCleanupsClass:
93
0
  case Stmt::GenericSelectionExprClass:
94
0
  case Stmt::OpaqueValueExprClass:
95
0
  case Stmt::ConstantExprClass:
96
0
  case Stmt::ParenExprClass:
97
0
  case Stmt::SubstNonTypeTemplateParmExprClass:
98
0
    llvm_unreachable("Should have been handled by ignoreTransparentExprs");
99
0
100
73.2k
  case Stmt::AddrLabelExprClass:
101
73.2k
  case Stmt::CharacterLiteralClass:
102
73.2k
  case Stmt::CXXBoolLiteralExprClass:
103
73.2k
  case Stmt::CXXScalarValueInitExprClass:
104
73.2k
  case Stmt::ImplicitValueInitExprClass:
105
73.2k
  case Stmt::IntegerLiteralClass:
106
73.2k
  case Stmt::ObjCBoolLiteralExprClass:
107
73.2k
  case Stmt::CXXNullPtrLiteralExprClass:
108
73.2k
  case Stmt::ObjCStringLiteralClass:
109
73.2k
  case Stmt::StringLiteralClass:
110
73.2k
  case Stmt::TypeTraitExprClass:
111
73.2k
    // Known constants; defer to SValBuilder.
112
73.2k
    return svalBuilder.getConstantVal(cast<Expr>(S)).getValue();
113
73.2k
114
73.2k
  case Stmt::ReturnStmtClass: {
115
15.7k
    const auto *RS = cast<ReturnStmt>(S);
116
15.7k
    if (const Expr *RE = RS->getRetValue())
117
13.8k
      return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
118
1.87k
    return UndefinedVal();
119
1.87k
  }
120
1.87k
121
1.87k
  // Handle all other Stmt* using a lookup.
122
1.32M
  default:
123
1.32M
    return lookupExpr(EnvironmentEntry(S, LCtx));
124
1.41M
  }
125
1.41M
}
126
127
Environment EnvironmentManager::bindExpr(Environment Env,
128
                                         const EnvironmentEntry &E,
129
                                         SVal V,
130
761k
                                         bool Invalidate) {
131
761k
  if (V.isUnknown()) {
132
26.8k
    if (Invalidate)
133
26.8k
      return Environment(F.remove(Env.ExprBindings, E));
134
0
    else
135
0
      return Env;
136
734k
  }
137
734k
  return Environment(F.add(Env.ExprBindings, E, V));
138
734k
}
139
140
namespace {
141
142
class MarkLiveCallback final : public SymbolVisitor {
143
  SymbolReaper &SymReaper;
144
145
public:
146
320k
  MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
147
148
422k
  bool VisitSymbol(SymbolRef sym) override {
149
422k
    SymReaper.markLive(sym);
150
422k
    return true;
151
422k
  }
152
153
844k
  bool VisitMemRegion(const MemRegion *R) override {
154
844k
    SymReaper.markLive(R);
155
844k
    return true;
156
844k
  }
157
};
158
159
} // namespace
160
161
// removeDeadBindings:
162
//  - Remove subexpression bindings.
163
//  - Remove dead block expression bindings.
164
//  - Keep live block expression bindings:
165
//   - Mark their reachable symbols live in SymbolReaper,
166
//     see ScanReachableSymbols.
167
//   - Mark the region in DRoots if the binding is a loc::MemRegionVal.
168
Environment
169
EnvironmentManager::removeDeadBindings(Environment Env,
170
                                       SymbolReaper &SymReaper,
171
320k
                                       ProgramStateRef ST) {
172
320k
  // We construct a new Environment object entirely, as this is cheaper than
173
320k
  // individually removing all the subexpression bindings (which will greatly
174
320k
  // outnumber block-level expression bindings).
175
320k
  Environment NewEnv = getInitialEnvironment();
176
320k
177
320k
  MarkLiveCallback CB(SymReaper);
178
320k
  ScanReachableSymbols RSScaner(ST, CB);
179
320k
180
320k
  llvm::ImmutableMapRef<EnvironmentEntry, SVal>
181
320k
    EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
182
320k
             F.getTreeFactory());
183
320k
184
320k
  // Iterate over the block-expr bindings.
185
320k
  for (Environment::iterator I = Env.begin(), E = Env.end();
186
2.20M
       I != E; 
++I1.88M
) {
187
1.88M
    const EnvironmentEntry &BlkExpr = I.getKey();
188
1.88M
    const SVal &X = I.getData();
189
1.88M
190
1.88M
    if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
191
1.06M
      // Copy the binding to the new map.
192
1.06M
      EBMapRef = EBMapRef.add(BlkExpr, X);
193
1.06M
194
1.06M
      // Mark all symbols in the block expr's value live.
195
1.06M
      RSScaner.scan(X);
196
1.06M
    }
197
1.88M
  }
198
320k
199
320k
  NewEnv.ExprBindings = EBMapRef.asImmutableMap();
200
320k
  return NewEnv;
201
320k
}
202
203
void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
204
                            const LocationContext *LCtx, const char *NL,
205
4
                            unsigned int Space, bool IsDot) const {
206
4
  Indent(Out, Space, IsDot) << "\"environment\": ";
207
4
208
4
  if (ExprBindings.isEmpty()) {
209
0
    Out << "null," << NL;
210
0
    return;
211
0
  }
212
4
213
4
  ++Space;
214
4
  if (!LCtx) {
215
4
    // Find the freshest location context.
216
4
    llvm::SmallPtrSet<const LocationContext *, 16> FoundContexts;
217
4
    for (const auto &I : *this) {
218
4
      const LocationContext *LC = I.first.getLocationContext();
219
4
      if (FoundContexts.count(LC) == 0) {
220
4
        // This context is fresher than all other contexts so far.
221
4
        LCtx = LC;
222
8
        for (const LocationContext *LCI = LC; LCI; 
LCI = LCI->getParent()4
)
223
4
          FoundContexts.insert(LCI);
224
4
      }
225
4
    }
226
4
  }
227
4
228
4
  assert(LCtx);
229
4
230
4
  Out << "{ \"pointer\": \"" << (const void *)LCtx->getStackFrame()
231
4
      << "\", \"items\": [" << NL;
232
4
  PrintingPolicy PP = Ctx.getPrintingPolicy();
233
4
234
4
  LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
235
4
    // LCtx items begin
236
4
    bool HasItem = false;
237
4
    unsigned int InnerSpace = Space + 1;
238
4
239
4
    // Store the last ExprBinding which we will print.
240
4
    BindingsTy::iterator LastI = ExprBindings.end();
241
8
    for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
242
4
         ++I) {
243
4
      if (I->first.getLocationContext() != LC)
244
0
        continue;
245
4
246
4
      if (!HasItem) {
247
4
        HasItem = true;
248
4
        Out << '[' << NL;
249
4
      }
250
4
251
4
      const Stmt *S = I->first.getStmt();
252
4
      (void)S;
253
4
      assert(S != nullptr && "Expected non-null Stmt");
254
4
255
4
      LastI = I;
256
4
    }
257
4
258
8
    for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
259
4
         ++I) {
260
4
      if (I->first.getLocationContext() != LC)
261
0
        continue;
262
4
263
4
      const Stmt *S = I->first.getStmt();
264
4
      Indent(Out, InnerSpace, IsDot)
265
4
          << "{ \"stmt_id\": " << S->getID(Ctx) << ", \"pretty\": ";
266
4
      S->printJson(Out, nullptr, PP, /*AddQuotes=*/true);
267
4
268
4
      Out << ", \"value\": ";
269
4
      I->second.printJson(Out, /*AddQuotes=*/true);
270
4
271
4
      Out << " }";
272
4
273
4
      if (I != LastI)
274
0
        Out << ',';
275
4
      Out << NL;
276
4
    }
277
4
278
4
    if (HasItem)
279
4
      Indent(Out, --InnerSpace, IsDot) << ']';
280
0
    else
281
0
      Out << "null ";
282
4
  });
283
4
284
4
  Indent(Out, --Space, IsDot) << "]}," << NL;
285
4
}