Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- SVals.cpp - Abstract RValues for Path-Sens. Value Tracking --------===//
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 SVal, Loc, and NonLoc, classes that represent
10
//  abstract r-values for use with path-sensitive value tracking.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
15
#include "clang/AST/ASTContext.h"
16
#include "clang/AST/Decl.h"
17
#include "clang/AST/DeclCXX.h"
18
#include "clang/AST/Expr.h"
19
#include "clang/AST/Type.h"
20
#include "clang/Basic/JsonSupport.h"
21
#include "clang/Basic/LLVM.h"
22
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
23
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
24
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
25
#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
26
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
27
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
28
#include "llvm/Support/Casting.h"
29
#include "llvm/Support/Compiler.h"
30
#include "llvm/Support/ErrorHandling.h"
31
#include "llvm/Support/raw_ostream.h"
32
#include <cassert>
33
#include <optional>
34
35
using namespace clang;
36
using namespace ento;
37
38
//===----------------------------------------------------------------------===//
39
// Symbol iteration within an SVal.
40
//===----------------------------------------------------------------------===//
41
42
//===----------------------------------------------------------------------===//
43
// Utility methods.
44
//===----------------------------------------------------------------------===//
45
46
26.9k
const FunctionDecl *SVal::getAsFunctionDecl() const {
47
26.9k
  if (std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
48
26.4k
    const MemRegion* R = X->getRegion();
49
26.4k
    if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>())
50
25.3k
      if (const auto *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
51
25.3k
        return FD;
52
26.4k
  }
53
54
1.56k
  if (auto X = getAs<nonloc::PointerToMember>()) {
55
410
    if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(X->getDecl()))
56
410
      return MD;
57
410
  }
58
1.15k
  return nullptr;
59
1.56k
}
60
61
/// If this SVal is a location (subclasses Loc) and wraps a symbol,
62
/// return that SymbolRef.  Otherwise return 0.
63
///
64
/// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
65
/// region. If that is the case, gets the underlining region.
66
/// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic,
67
/// the first symbolic parent region is returned.
68
2.27M
SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const {
69
  // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
70
2.27M
  if (const MemRegion *R = getAsRegion())
71
918k
    if (const SymbolicRegion *SymR =
72
918k
            IncludeBaseRegions ? R->getSymbolicBase()
73
918k
                               : dyn_cast<SymbolicRegion>(R->StripCasts()))
74
502k
      return SymR->getSymbol();
75
76
1.76M
  return nullptr;
77
2.27M
}
78
79
/// Get the symbol in the SVal or its base region.
80
76.9k
SymbolRef SVal::getLocSymbolInBase() const {
81
76.9k
  std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
82
83
76.9k
  if (!X)
84
4
    return nullptr;
85
86
76.9k
  const MemRegion *R = X->getRegion();
87
88
180k
  while (const auto *SR = dyn_cast<SubRegion>(R)) {
89
116k
    if (const auto *SymR = dyn_cast<SymbolicRegion>(SR))
90
13.7k
      return SymR->getSymbol();
91
103k
    else
92
103k
      R = SR->getSuperRegion();
93
116k
  }
94
95
63.2k
  return nullptr;
96
76.9k
}
97
98
/// If this SVal wraps a symbol return that SymbolRef.
99
/// Otherwise, return 0.
100
///
101
/// Casts are ignored during lookup.
102
/// \param IncludeBaseRegions The boolean that controls whether the search
103
/// should continue to the base regions if the region is not symbolic.
104
9.38M
SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const {
105
  // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
106
9.38M
  if (std::optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
107
7.15M
    return X->getSymbol();
108
109
2.22M
  return getAsLocSymbol(IncludeBaseRegions);
110
9.38M
}
111
112
536
const llvm::APSInt *SVal::getAsInteger() const {
113
536
  if (auto CI = getAs<nonloc::ConcreteInt>())
114
515
    return &CI->getValue();
115
21
  if (auto CI = getAs<loc::ConcreteInt>())
116
0
    return &CI->getValue();
117
21
  return nullptr;
118
21
}
119
120
6.33M
const MemRegion *SVal::getAsRegion() const {
121
6.33M
  if (std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>())
122
3.34M
    return X->getRegion();
123
124
2.98M
  if (std::optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
125
1.53k
    return X->getLoc().getAsRegion();
126
127
2.98M
  return nullptr;
128
2.98M
}
129
130
namespace {
131
class TypeRetrievingVisitor
132
    : public FullSValVisitor<TypeRetrievingVisitor, QualType> {
133
private:
134
  const ASTContext &Context;
135
136
public:
137
237k
  TypeRetrievingVisitor(const ASTContext &Context) : Context(Context) {}
138
139
66.7k
  QualType VisitLocMemRegionVal(loc::MemRegionVal MRV) {
140
66.7k
    return Visit(MRV.getRegion());
141
66.7k
  }
142
138
  QualType VisitLocGotoLabel(loc::GotoLabel GL) {
143
138
    return QualType{Context.VoidPtrTy};
144
138
  }
145
170k
  template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) {
146
170k
    const llvm::APSInt &Value = CI.getValue();
147
170k
    if (1 == Value.getBitWidth())
148
42
      return Context.BoolTy;
149
169k
    return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned());
150
170k
  }
SVals.cpp:clang::QualType (anonymous namespace)::TypeRetrievingVisitor::VisitConcreteInt<clang::ento::loc::ConcreteInt>(clang::ento::loc::ConcreteInt)
Line
Count
Source
145
43.2k
  template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) {
146
43.2k
    const llvm::APSInt &Value = CI.getValue();
147
43.2k
    if (1 == Value.getBitWidth())
148
0
      return Context.BoolTy;
149
43.2k
    return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned());
150
43.2k
  }
SVals.cpp:clang::QualType (anonymous namespace)::TypeRetrievingVisitor::VisitConcreteInt<clang::ento::nonloc::ConcreteInt>(clang::ento::nonloc::ConcreteInt)
Line
Count
Source
145
126k
  template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) {
146
126k
    const llvm::APSInt &Value = CI.getValue();
147
126k
    if (1 == Value.getBitWidth())
148
42
      return Context.BoolTy;
149
126k
    return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned());
150
126k
  }
151
43.2k
  QualType VisitLocConcreteInt(loc::ConcreteInt CI) {
152
43.2k
    return VisitConcreteInt(CI);
153
43.2k
  }
154
126k
  QualType VisitNonLocConcreteInt(nonloc::ConcreteInt CI) {
155
126k
    return VisitConcreteInt(CI);
156
126k
  }
157
84
  QualType VisitNonLocLocAsInteger(nonloc::LocAsInteger LI) {
158
84
    QualType NestedType = Visit(LI.getLoc());
159
84
    if (NestedType.isNull())
160
0
      return NestedType;
161
162
84
    return Context.getIntTypeForBitwidth(LI.getNumBits(),
163
84
                                         NestedType->isSignedIntegerType());
164
84
  }
165
126
  QualType VisitNonLocCompoundVal(nonloc::CompoundVal CV) {
166
126
    return CV.getValue()->getType();
167
126
  }
168
21
  QualType VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal LCV) {
169
21
    return LCV.getRegion()->getValueType();
170
21
  }
171
298
  QualType VisitNonLocSymbolVal(nonloc::SymbolVal SV) {
172
298
    return Visit(SV.getSymbol());
173
298
  }
174
41.5k
  QualType VisitSymbolicRegion(const SymbolicRegion *SR) {
175
41.5k
    return Visit(SR->getSymbol());
176
41.5k
  }
177
70
  QualType VisitAllocaRegion(const AllocaRegion *) {
178
70
    return QualType{Context.VoidPtrTy};
179
70
  }
180
25.0k
  QualType VisitTypedRegion(const TypedRegion *TR) {
181
25.0k
    return TR->getLocationType();
182
25.0k
  }
183
41.8k
  QualType VisitSymExpr(const SymExpr *SE) { return SE->getType(); }
184
};
185
} // end anonymous namespace
186
187
237k
QualType SVal::getType(const ASTContext &Context) const {
188
237k
  TypeRetrievingVisitor TRV{Context};
189
237k
  return TRV.Visit(*this);
190
237k
}
191
192
517
const MemRegion *loc::MemRegionVal::stripCasts(bool StripBaseCasts) const {
193
517
  return getRegion()->StripCasts(StripBaseCasts);
194
517
}
195
196
69.7k
const void *nonloc::LazyCompoundVal::getStore() const {
197
69.7k
  return static_cast<const LazyCompoundValData*>(Data)->getStore();
198
69.7k
}
199
200
98.3k
const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const {
201
98.3k
  return static_cast<const LazyCompoundValData*>(Data)->getRegion();
202
98.3k
}
203
204
95
bool nonloc::PointerToMember::isNullMemberPointer() const {
205
95
  return getPTMData().isNull();
206
95
}
207
208
469
const NamedDecl *nonloc::PointerToMember::getDecl() const {
209
469
  const auto PTMD = this->getPTMData();
210
469
  if (PTMD.isNull())
211
0
    return nullptr;
212
213
469
  const NamedDecl *ND = nullptr;
214
469
  if (PTMD.is<const NamedDecl *>())
215
421
    ND = PTMD.get<const NamedDecl *>();
216
48
  else
217
48
    ND = PTMD.get<const PointerToMemberData *>()->getDeclaratorDecl();
218
219
469
  return ND;
220
469
}
221
222
//===----------------------------------------------------------------------===//
223
// Other Iterators.
224
//===----------------------------------------------------------------------===//
225
226
4.87k
nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
227
4.87k
  return getValue()->begin();
228
4.87k
}
229
230
4.86k
nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
231
4.86k
  return getValue()->end();
232
4.86k
}
233
234
17
nonloc::PointerToMember::iterator nonloc::PointerToMember::begin() const {
235
17
  const PTMDataType PTMD = getPTMData();
236
17
  if (PTMD.is<const NamedDecl *>())
237
7
    return {};
238
10
  return PTMD.get<const PointerToMemberData *>()->begin();
239
17
}
240
241
17
nonloc::PointerToMember::iterator nonloc::PointerToMember::end() const {
242
17
  const PTMDataType PTMD = getPTMData();
243
17
  if (PTMD.is<const NamedDecl *>())
244
7
    return {};
245
10
  return PTMD.get<const PointerToMemberData *>()->end();
246
17
}
247
248
//===----------------------------------------------------------------------===//
249
// Useful predicates.
250
//===----------------------------------------------------------------------===//
251
252
123k
bool SVal::isConstant() const {
253
123k
  return getAs<nonloc::ConcreteInt>() || 
getAs<loc::ConcreteInt>()84.9k
;
254
123k
}
255
256
260k
bool SVal::isConstant(int I) const {
257
260k
  if (std::optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>())
258
7.07k
    return LV->getValue() == I;
259
252k
  if (std::optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>())
260
78.4k
    return NV->getValue() == I;
261
174k
  return false;
262
252k
}
263
264
260k
bool SVal::isZeroConstant() const {
265
260k
  return isConstant(0);
266
260k
}
267
268
//===----------------------------------------------------------------------===//
269
// Pretty-Printing.
270
//===----------------------------------------------------------------------===//
271
272
0
LLVM_DUMP_METHOD void SVal::dump() const { dumpToStream(llvm::errs()); }
273
274
352
void SVal::printJson(raw_ostream &Out, bool AddQuotes) const {
275
352
  std::string Buf;
276
352
  llvm::raw_string_ostream TempOut(Buf);
277
278
352
  dumpToStream(TempOut);
279
280
352
  Out << JsonFormat(TempOut.str(), AddQuotes);
281
352
}
282
283
4.13k
void SVal::dumpToStream(raw_ostream &os) const {
284
4.13k
  switch (getBaseKind()) {
285
19
    case UnknownValKind:
286
19
      os << "Unknown";
287
19
      break;
288
3.62k
    case NonLocKind:
289
3.62k
      castAs<NonLoc>().dumpToStream(os);
290
3.62k
      break;
291
476
    case LocKind:
292
476
      castAs<Loc>().dumpToStream(os);
293
476
      break;
294
16
    case UndefinedValKind:
295
16
      os << "Undefined";
296
16
      break;
297
4.13k
  }
298
4.13k
}
299
300
3.62k
void NonLoc::dumpToStream(raw_ostream &os) const {
301
3.62k
  switch (getSubKind()) {
302
521
    case nonloc::ConcreteIntKind: {
303
521
      const auto &Value = castAs<nonloc::ConcreteInt>().getValue();
304
521
      os << Value << ' ' << (Value.isSigned() ? 
'S'518
:
'U'3
)
305
521
         << Value.getBitWidth() << 'b';
306
521
      break;
307
0
    }
308
3.08k
    case nonloc::SymbolValKind:
309
3.08k
      os << castAs<nonloc::SymbolVal>().getSymbol();
310
3.08k
      break;
311
312
9
    case nonloc::LocAsIntegerKind: {
313
9
      const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>();
314
9
      os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
315
9
      break;
316
0
    }
317
0
    case nonloc::CompoundValKind: {
318
0
      const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>();
319
0
      os << "compoundVal{";
320
0
      bool first = true;
321
0
      for (const auto &I : C) {
322
0
        if (first) {
323
0
          os << ' '; first = false;
324
0
        }
325
0
        else
326
0
          os << ", ";
327
328
0
        I.dumpToStream(os);
329
0
      }
330
0
      os << "}";
331
0
      break;
332
0
    }
333
11
    case nonloc::LazyCompoundValKind: {
334
11
      const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>();
335
11
      os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
336
11
         << ',' << C.getRegion()
337
11
         << '}';
338
11
      break;
339
0
    }
340
0
    case nonloc::PointerToMemberKind: {
341
0
      os << "pointerToMember{";
342
0
      const nonloc::PointerToMember &CastRes =
343
0
          castAs<nonloc::PointerToMember>();
344
0
      if (CastRes.getDecl())
345
0
        os << "|" << CastRes.getDecl()->getQualifiedNameAsString() << "|";
346
0
      bool first = true;
347
0
      for (const auto &I : CastRes) {
348
0
        if (first) {
349
0
          os << ' '; first = false;
350
0
        }
351
0
        else
352
0
          os << ", ";
353
354
0
        os << I->getType();
355
0
      }
356
357
0
      os << '}';
358
0
      break;
359
0
    }
360
0
    default:
361
0
      assert(false && "Pretty-printed not implemented for this NonLoc.");
362
0
      break;
363
3.62k
  }
364
3.62k
}
365
366
476
void Loc::dumpToStream(raw_ostream &os) const {
367
476
  switch (getSubKind()) {
368
70
    case loc::ConcreteIntKind:
369
70
      os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)";
370
70
      break;
371
0
    case loc::GotoLabelKind:
372
0
      os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
373
0
      break;
374
406
    case loc::MemRegionValKind:
375
406
      os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
376
406
      break;
377
0
    default:
378
0
      llvm_unreachable("Pretty-printing not implemented for this Loc.");
379
476
  }
380
476
}