Coverage Report

Created: 2023-09-12 09:32

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