Coverage Report

Created: 2020-02-15 09:57

/Users/buildslave/jenkins/workspace/coverage/llvm-project/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
4.66M
static const Expr *ignoreTransparentExprs(const Expr *E) {
38
4.66M
  E = E->IgnoreParens();
39
4.66M
40
4.66M
  switch (E->getStmtClass()) {
41
3.38k
  case Stmt::OpaqueValueExprClass:
42
3.38k
    E = cast<OpaqueValueExpr>(E)->getSourceExpr();
43
3.38k
    break;
44
9.49k
  case Stmt::ExprWithCleanupsClass:
45
9.49k
    E = cast<ExprWithCleanups>(E)->getSubExpr();
46
9.49k
    break;
47
0
  case Stmt::ConstantExprClass:
48
0
    E = cast<ConstantExpr>(E)->getSubExpr();
49
0
    break;
50
2.27k
  case Stmt::CXXBindTemporaryExprClass:
51
2.27k
    E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
52
2.27k
    break;
53
14
  case Stmt::SubstNonTypeTemplateParmExprClass:
54
14
    E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
55
14
    break;
56
4.64M
  default:
57
4.64M
    // This is the base case: we can't look through more than we already have.
58
4.64M
    return E;
59
15.1k
  }
60
15.1k
61
15.1k
  return ignoreTransparentExprs(E);
62
15.1k
}
63
64
4.67M
static const Stmt *ignoreTransparentExprs(const Stmt *S) {
65
4.67M
  if (const auto *E = dyn_cast<Expr>(S))
66
4.64M
    return ignoreTransparentExprs(E);
67
24.6k
  return S;
68
24.6k
}
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
4.67M
                                             : nullptr) {}
75
76
1.78M
SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
77
1.78M
  const SVal* X = ExprBindings.lookup(E);
78
1.78M
  if (X) {
79
1.68M
    SVal V = *X;
80
1.68M
    return V;
81
1.68M
  }
82
100k
  return UnknownVal();
83
100k
}
84
85
SVal Environment::getSVal(const EnvironmentEntry &Entry,
86
1.87M
                          SValBuilder& svalBuilder) const {
87
1.87M
  const Stmt *S = Entry.getStmt();
88
1.87M
  const LocationContext *LCtx = Entry.getLocationContext();
89
1.87M
90
1.87M
  switch (S->getStmtClass()) {
91
0
  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
75.7k
  case Stmt::AddrLabelExprClass:
101
75.7k
  case Stmt::CharacterLiteralClass:
102
75.7k
  case Stmt::CXXBoolLiteralExprClass:
103
75.7k
  case Stmt::CXXScalarValueInitExprClass:
104
75.7k
  case Stmt::ImplicitValueInitExprClass:
105
75.7k
  case Stmt::IntegerLiteralClass:
106
75.7k
  case Stmt::ObjCBoolLiteralExprClass:
107
75.7k
  case Stmt::CXXNullPtrLiteralExprClass:
108
75.7k
  case Stmt::ObjCStringLiteralClass:
109
75.7k
  case Stmt::StringLiteralClass:
110
75.7k
  case Stmt::TypeTraitExprClass:
111
75.7k
  case Stmt::SizeOfPackExprClass:
112
75.7k
    // Known constants; defer to SValBuilder.
113
75.7k
    return svalBuilder.getConstantVal(cast<Expr>(S)).getValue();
114
75.7k
115
75.7k
  case Stmt::ReturnStmtClass: {
116
21.5k
    const auto *RS = cast<ReturnStmt>(S);
117
21.5k
    if (const Expr *RE = RS->getRetValue())
118
19.6k
      return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
119
1.92k
    return UndefinedVal();
120
1.92k
  }
121
1.92k
122
1.92k
  // Handle all other Stmt* using a lookup.
123
1.78M
  default:
124
1.78M
    return lookupExpr(EnvironmentEntry(S, LCtx));
125
1.87M
  }
126
1.87M
}
127
128
Environment EnvironmentManager::bindExpr(Environment Env,
129
                                         const EnvironmentEntry &E,
130
                                         SVal V,
131
1.01M
                                         bool Invalidate) {
132
1.01M
  if (V.isUnknown()) {
133
49.2k
    if (Invalidate)
134
49.2k
      return Environment(F.remove(Env.ExprBindings, E));
135
0
    else
136
0
      return Env;
137
965k
  }
138
965k
  return Environment(F.add(Env.ExprBindings, E, V));
139
965k
}
140
141
namespace {
142
143
class MarkLiveCallback final : public SymbolVisitor {
144
  SymbolReaper &SymReaper;
145
146
public:
147
470k
  MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
148
149
575k
  bool VisitSymbol(SymbolRef sym) override {
150
575k
    SymReaper.markLive(sym);
151
575k
    return true;
152
575k
  }
153
154
1.42M
  bool VisitMemRegion(const MemRegion *R) override {
155
1.42M
    SymReaper.markLive(R);
156
1.42M
    return true;
157
1.42M
  }
158
};
159
160
} // namespace
161
162
// removeDeadBindings:
163
//  - Remove subexpression bindings.
164
//  - Remove dead block expression bindings.
165
//  - Keep live block expression bindings:
166
//   - Mark their reachable symbols live in SymbolReaper,
167
//     see ScanReachableSymbols.
168
//   - Mark the region in DRoots if the binding is a loc::MemRegionVal.
169
Environment
170
EnvironmentManager::removeDeadBindings(Environment Env,
171
                                       SymbolReaper &SymReaper,
172
470k
                                       ProgramStateRef ST) {
173
470k
  // We construct a new Environment object entirely, as this is cheaper than
174
470k
  // individually removing all the subexpression bindings (which will greatly
175
470k
  // outnumber block-level expression bindings).
176
470k
  Environment NewEnv = getInitialEnvironment();
177
470k
178
470k
  MarkLiveCallback CB(SymReaper);
179
470k
  ScanReachableSymbols RSScaner(ST, CB);
180
470k
181
470k
  llvm::ImmutableMapRef<EnvironmentEntry, SVal>
182
470k
    EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
183
470k
             F.getTreeFactory());
184
470k
185
470k
  // Iterate over the block-expr bindings.
186
470k
  for (Environment::iterator I = Env.begin(), E = Env.end();
187
3.32M
       I != E; 
++I2.85M
) {
188
2.85M
    const EnvironmentEntry &BlkExpr = I.getKey();
189
2.85M
    const SVal &X = I.getData();
190
2.85M
191
2.85M
    if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
192
1.78M
      // Copy the binding to the new map.
193
1.78M
      EBMapRef = EBMapRef.add(BlkExpr, X);
194
1.78M
195
1.78M
      // Mark all symbols in the block expr's value live.
196
1.78M
      RSScaner.scan(X);
197
1.78M
    }
198
2.85M
  }
199
470k
200
470k
  NewEnv.ExprBindings = EBMapRef.asImmutableMap();
201
470k
  return NewEnv;
202
470k
}
203
204
void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
205
                            const LocationContext *LCtx, const char *NL,
206
107
                            unsigned int Space, bool IsDot) const {
207
107
  Indent(Out, Space, IsDot) << "\"environment\": ";
208
107
209
107
  if (ExprBindings.isEmpty()) {
210
34
    Out << "null," << NL;
211
34
    return;
212
34
  }
213
73
214
73
  ++Space;
215
73
  if (!LCtx) {
216
19
    // Find the freshest location context.
217
19
    llvm::SmallPtrSet<const LocationContext *, 16> FoundContexts;
218
19
    for (const auto &I : *this) {
219
19
      const LocationContext *LC = I.first.getLocationContext();
220
19
      if (FoundContexts.count(LC) == 0) {
221
19
        // This context is fresher than all other contexts so far.
222
19
        LCtx = LC;
223
38
        for (const LocationContext *LCI = LC; LCI; 
LCI = LCI->getParent()19
)
224
19
          FoundContexts.insert(LCI);
225
19
      }
226
19
    }
227
19
  }
228
73
229
73
  assert(LCtx);
230
73
231
73
  Out << "{ \"pointer\": \"" << (const void *)LCtx->getStackFrame()
232
73
      << "\", \"items\": [" << NL;
233
73
  PrintingPolicy PP = Ctx.getPrintingPolicy();
234
73
235
78
  LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
236
78
    // LCtx items begin
237
78
    bool HasItem = false;
238
78
    unsigned int InnerSpace = Space + 1;
239
78
240
78
    // Store the last ExprBinding which we will print.
241
78
    BindingsTy::iterator LastI = ExprBindings.end();
242
182
    for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
243
104
         ++I) {
244
104
      if (I->first.getLocationContext() != LC)
245
5
        continue;
246
99
247
99
      if (!HasItem) {
248
73
        HasItem = true;
249
73
        Out << '[' << NL;
250
73
      }
251
99
252
99
      const Stmt *S = I->first.getStmt();
253
99
      (void)S;
254
99
      assert(S != nullptr && "Expected non-null Stmt");
255
99
256
99
      LastI = I;
257
99
    }
258
78
259
182
    for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
260
104
         ++I) {
261
104
      if (I->first.getLocationContext() != LC)
262
5
        continue;
263
99
264
99
      const Stmt *S = I->first.getStmt();
265
99
      Indent(Out, InnerSpace, IsDot)
266
99
          << "{ \"stmt_id\": " << S->getID(Ctx) << ", \"pretty\": ";
267
99
      S->printJson(Out, nullptr, PP, /*AddQuotes=*/true);
268
99
269
99
      Out << ", \"value\": ";
270
99
      I->second.printJson(Out, /*AddQuotes=*/true);
271
99
272
99
      Out << " }";
273
99
274
99
      if (I != LastI)
275
26
        Out << ',';
276
99
      Out << NL;
277
99
    }
278
78
279
78
    if (HasItem)
280
73
      Indent(Out, --InnerSpace, IsDot) << ']';
281
5
    else
282
5
      Out << "null ";
283
78
  });
284
73
285
73
  Indent(Out, --Space, IsDot) << "]}," << NL;
286
73
}