Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===- SVals.h - Abstract Values for Static Analysis ------------*- 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 SVal, Loc, and NonLoc, classes that represent
10
//  abstract r-values for use with path-sensitive value tracking.
11
//
12
//===----------------------------------------------------------------------===//
13
 
14
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
15
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
16
 
17
#include "clang/AST/Expr.h"
18
#include "clang/AST/Type.h"
19
#include "clang/Basic/LLVM.h"
20
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
21
#include "llvm/ADT/FoldingSet.h"
22
#include "llvm/ADT/ImmutableList.h"
23
#include "llvm/ADT/PointerUnion.h"
24
#include "llvm/Support/Casting.h"
25
#include <cassert>
26
#include <cstdint>
27
#include <optional>
28
#include <utility>
29
 
30
//==------------------------------------------------------------------------==//
31
//  Base SVal types.
32
//==------------------------------------------------------------------------==//
33
 
34
namespace clang {
35
 
36
class CXXBaseSpecifier;
37
class FunctionDecl;
38
class LabelDecl;
39
 
40
namespace ento {
41
 
42
class CompoundValData;
43
class LazyCompoundValData;
44
class MemRegion;
45
class PointerToMemberData;
46
class SValBuilder;
47
class TypedValueRegion;
48
 
49
namespace nonloc {
50
 
51
/// Sub-kinds for NonLoc values.
52
enum Kind {
53
#define NONLOC_SVAL(Id, Parent) Id ## Kind,
54
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
55
};
56
 
57
} // namespace nonloc
58
 
59
namespace loc {
60
 
61
/// Sub-kinds for Loc values.
62
enum Kind {
63
#define LOC_SVAL(Id, Parent) Id ## Kind,
64
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
65
};
66
 
67
} // namespace loc
68
 
69
/// SVal - This represents a symbolic expression, which can be either
70
///  an L-value or an R-value.
71
///
72
class SVal {
73
public:
74
  enum BaseKind {
75
    // The enumerators must be representable using 2 bits.
76
#define BASIC_SVAL(Id, Parent) Id ## Kind,
77
#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind,
78
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
79
  };
80
  enum { BaseBits = 2, BaseMask = 0b11 };
81
 
82
protected:
83
  const void *Data = nullptr;
84
 
85
  /// The lowest 2 bits are a BaseKind (0 -- 3).
86
  ///  The higher bits are an unsigned "kind" value.
87
  unsigned Kind = 0;
88
 
89
  explicit SVal(const void *d, bool isLoc, unsigned ValKind)
90
      : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
91
 
92
  explicit SVal(BaseKind k, const void *D = nullptr) : Data(D), Kind(k) {}
93
 
94
public:
95
  explicit SVal() = default;
96
 
97
  /// Convert to the specified SVal type, asserting that this SVal is of
98
  /// the desired type.
99
  template <typename T> T castAs() const { return llvm::cast<T>(*this); }
100
 
101
  /// Convert to the specified SVal type, returning std::nullopt if this SVal is
102
  /// not of the desired type.
103
  template <typename T> std::optional<T> getAs() const {
104
    return llvm::dyn_cast<T>(*this);
105
  }
106
 
107
  unsigned getRawKind() const { return Kind; }
108
  BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
109
  unsigned getSubKind() const { return Kind >> BaseBits; }
110
 
111
  // This method is required for using SVal in a FoldingSetNode.  It
112
  // extracts a unique signature for this SVal object.
113
  void Profile(llvm::FoldingSetNodeID &ID) const {
114
    ID.AddInteger((unsigned) getRawKind());
115
    ID.AddPointer(Data);
116
  }
117
 
118
  bool operator==(SVal R) const {
119
    return getRawKind() == R.getRawKind() && Data == R.Data;
120
  }
121
 
122
  bool operator!=(SVal R) const { return !(*this == R); }
123
 
124
  bool isUnknown() const {
125
    return getRawKind() == UnknownValKind;
126
  }
127
 
128
  bool isUndef() const {
129
    return getRawKind() == UndefinedValKind;
130
  }
131
 
132
  bool isUnknownOrUndef() const {
133
    return getRawKind() <= UnknownValKind;
134
  }
135
 
136
  bool isValid() const {
137
    return getRawKind() > UnknownValKind;
138
  }
139
 
140
  bool isConstant() const;
141
 
142
  bool isConstant(int I) const;
143
 
144
  bool isZeroConstant() const;
145
 
146
  /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
147
  /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
148
  /// Otherwise return 0.
149
  const FunctionDecl *getAsFunctionDecl() const;
150
 
151
  /// If this SVal is a location and wraps a symbol, return that
152
  ///  SymbolRef. Otherwise return 0.
153
  ///
154
  /// Casts are ignored during lookup.
155
  /// \param IncludeBaseRegions The boolean that controls whether the search
156
  /// should continue to the base regions if the region is not symbolic.
157
  SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const;
158
 
159
  /// Get the symbol in the SVal or its base region.
160
  SymbolRef getLocSymbolInBase() const;
161
 
162
  /// If this SVal wraps a symbol return that SymbolRef.
163
  /// Otherwise, return 0.
164
  ///
165
  /// Casts are ignored during lookup.
166
  /// \param IncludeBaseRegions The boolean that controls whether the search
167
  /// should continue to the base regions if the region is not symbolic.
168
  SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const;
169
 
170
  /// If this SVal is loc::ConcreteInt or nonloc::ConcreteInt,
171
  /// return a pointer to APSInt which is held in it.
172
  /// Otherwise, return nullptr.
173
  const llvm::APSInt *getAsInteger() const;
174
 
175
  const MemRegion *getAsRegion() const;
176
 
177
  /// printJson - Pretty-prints in JSON format.
178
  void printJson(raw_ostream &Out, bool AddQuotes) const;
179
 
180
  void dumpToStream(raw_ostream &OS) const;
181
  void dump() const;
182
 
183
  SymExpr::symbol_iterator symbol_begin() const {
184
    const SymExpr *SE = getAsSymbol(/*IncludeBaseRegions=*/true);
185
    if (SE)
186
      return SE->symbol_begin();
187
    else
188
      return SymExpr::symbol_iterator();
189
  }
190
 
191
  SymExpr::symbol_iterator symbol_end() const {
192
    return SymExpr::symbol_end();
193
  }
194
 
195
  /// Try to get a reasonable type for the given value.
196
  ///
197
  /// \returns The best approximation of the value type or Null.
198
  /// In theory, all symbolic values should be typed, but this function
199
  /// is still a WIP and might have a few blind spots.
200
  ///
201
  /// \note This function should not be used when the user has access to the
202
  /// bound expression AST node as well, since AST always has exact types.
203
  ///
204
  /// \note Loc values are interpreted as pointer rvalues for the purposes of
205
  /// this method.
206
  QualType getType(const ASTContext &) const;
207
};
208
 
209
inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) {
210
  V.dumpToStream(os);
211
  return os;
212
}
213
 
214
class UndefinedVal : public SVal {
215
public:
216
  UndefinedVal() : SVal(UndefinedValKind) {}
217
  static bool classof(SVal V) { return V.getBaseKind() == UndefinedValKind; }
218
};
219
 
220
class DefinedOrUnknownSVal : public SVal {
221
public:
222
  // We want calling these methods to be a compiler error since they are
223
  // tautologically false.
224
  bool isUndef() const = delete;
225
  bool isValid() const = delete;
226
 
227
  static bool classof(SVal V) { return !V.isUndef(); }
228
 
229
protected:
230
  explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
231
      : SVal(d, isLoc, ValKind) {}
232
  explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr) : SVal(k, D) {}
233
};
234
 
235
class UnknownVal : public DefinedOrUnknownSVal {
236
public:
237
  explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {}
238
 
239
  static bool classof(SVal V) { return V.getBaseKind() == UnknownValKind; }
240
};
241
 
242
class DefinedSVal : public DefinedOrUnknownSVal {
243
public:
244
  // We want calling these methods to be a compiler error since they are
245
  // tautologically true/false.
246
  bool isUnknown() const = delete;
247
  bool isUnknownOrUndef() const = delete;
248
  bool isValid() const = delete;
249
 
250
  static bool classof(SVal V) { return !V.isUnknownOrUndef(); }
251
 
252
protected:
253
  explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
254
      : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
255
};
256
 
257
/// Represents an SVal that is guaranteed to not be UnknownVal.
258
class KnownSVal : public SVal {
259
public:
260
  KnownSVal(const DefinedSVal &V) : SVal(V) {}
261
  KnownSVal(const UndefinedVal &V) : SVal(V) {}
262
  static bool classof(SVal V) { return !V.isUnknown(); }
263
};
264
 
265
class NonLoc : public DefinedSVal {
266
protected:
267
  explicit NonLoc(unsigned SubKind, const void *d)
268
      : DefinedSVal(d, false, SubKind) {}
269
 
270
public:
271
  void dumpToStream(raw_ostream &Out) const;
272
 
273
  static bool isCompoundType(QualType T) {
274
    return T->isArrayType() || T->isRecordType() ||
275
           T->isAnyComplexType() || T->isVectorType();
276
  }
277
 
278
  static bool classof(SVal V) { return V.getBaseKind() == NonLocKind; }
279
};
280
 
281
class Loc : public DefinedSVal {
282
protected:
283
  explicit Loc(unsigned SubKind, const void *D)
284
      : DefinedSVal(const_cast<void *>(D), true, SubKind) {}
285
 
286
public:
287
  void dumpToStream(raw_ostream &Out) const;
288
 
289
  static bool isLocType(QualType T) {
290
    return T->isAnyPointerType() || T->isBlockPointerType() ||
291
           T->isReferenceType() || T->isNullPtrType();
292
  }
293
 
294
  static bool classof(SVal V) { return V.getBaseKind() == LocKind; }
295
};
296
 
297
//==------------------------------------------------------------------------==//
298
//  Subclasses of NonLoc.
299
//==------------------------------------------------------------------------==//
300
 
301
namespace nonloc {
302
 
303
/// Represents symbolic expression that isn't a location.
304
class SymbolVal : public NonLoc {
305
public:
306
  SymbolVal() = delete;
307
  SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {
308
    assert(sym);
309
    assert(!Loc::isLocType(sym->getType()));
310
  }
311
 
312
  LLVM_ATTRIBUTE_RETURNS_NONNULL
313
  SymbolRef getSymbol() const {
314
    return (const SymExpr *) Data;
315
  }
316
 
317
  bool isExpression() const {
318
    return !isa<SymbolData>(getSymbol());
319
  }
320
 
321
  static bool classof(SVal V) {
322
    return V.getBaseKind() == NonLocKind && V.getSubKind() == SymbolValKind;
323
  }
324
 
325
  static bool classof(NonLoc V) { return V.getSubKind() == SymbolValKind; }
326
};
327
 
328
/// Value representing integer constant.
329
class ConcreteInt : public NonLoc {
330
public:
331
  explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
332
 
333
  const llvm::APSInt& getValue() const {
334
    return *static_cast<const llvm::APSInt *>(Data);
335
  }
336
 
337
  static bool classof(SVal V) {
338
    return V.getBaseKind() == NonLocKind && V.getSubKind() == ConcreteIntKind;
339
  }
340
 
341
  static bool classof(NonLoc V) { return V.getSubKind() == ConcreteIntKind; }
342
};
343
 
344
class LocAsInteger : public NonLoc {
345
  friend class ento::SValBuilder;
346
 
347
  explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data)
348
      : NonLoc(LocAsIntegerKind, &data) {
349
    // We do not need to represent loc::ConcreteInt as LocAsInteger,
350
    // as it'd collapse into a nonloc::ConcreteInt instead.
351
    assert(data.first.getBaseKind() == LocKind &&
352
           (data.first.getSubKind() == loc::MemRegionValKind ||
353
            data.first.getSubKind() == loc::GotoLabelKind));
354
  }
355
 
356
public:
357
  Loc getLoc() const {
358
    const std::pair<SVal, uintptr_t> *D =
359
      static_cast<const std::pair<SVal, uintptr_t> *>(Data);
360
    return D->first.castAs<Loc>();
361
  }
362
 
363
  unsigned getNumBits() const {
364
    const std::pair<SVal, uintptr_t> *D =
365
      static_cast<const std::pair<SVal, uintptr_t> *>(Data);
366
    return D->second;
367
  }
368
 
369
  static bool classof(SVal V) {
370
    return V.getBaseKind() == NonLocKind && V.getSubKind() == LocAsIntegerKind;
371
  }
372
 
373
  static bool classof(NonLoc V) { return V.getSubKind() == LocAsIntegerKind; }
374
};
375
 
376
class CompoundVal : public NonLoc {
377
  friend class ento::SValBuilder;
378
 
379
  explicit CompoundVal(const CompoundValData *D) : NonLoc(CompoundValKind, D) {
380
    assert(D);
381
  }
382
 
383
public:
384
  LLVM_ATTRIBUTE_RETURNS_NONNULL
385
  const CompoundValData* getValue() const {
386
    return static_cast<const CompoundValData *>(Data);
387
  }
388
 
389
  using iterator = llvm::ImmutableList<SVal>::iterator;
390
 
391
  iterator begin() const;
392
  iterator end() const;
393
 
394
  static bool classof(SVal V) {
395
    return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind;
396
  }
397
 
398
  static bool classof(NonLoc V) { return V.getSubKind() == CompoundValKind; }
399
};
400
 
401
class LazyCompoundVal : public NonLoc {
402
  friend class ento::SValBuilder;
403
 
404
  explicit LazyCompoundVal(const LazyCompoundValData *D)
405
      : NonLoc(LazyCompoundValKind, D) {
406
    assert(D);
407
  }
408
 
409
public:
410
  LLVM_ATTRIBUTE_RETURNS_NONNULL
411
  const LazyCompoundValData *getCVData() const {
412
    return static_cast<const LazyCompoundValData *>(Data);
413
  }
414
 
415
  /// It might return null.
416
  const void *getStore() const;
417
 
418
  LLVM_ATTRIBUTE_RETURNS_NONNULL
419
  const TypedValueRegion *getRegion() const;
420
 
421
  static bool classof(SVal V) {
422
    return V.getBaseKind() == NonLocKind &&
423
           V.getSubKind() == LazyCompoundValKind;
424
  }
425
 
426
  static bool classof(NonLoc V) {
427
    return V.getSubKind() == LazyCompoundValKind;
428
  }
429
};
430
 
431
/// Value representing pointer-to-member.
432
///
433
/// This value is qualified as NonLoc because neither loading nor storing
434
/// operations are applied to it. Instead, the analyzer uses the L-value coming
435
/// from pointer-to-member applied to an object.
436
/// This SVal is represented by a NamedDecl which can be a member function
437
/// pointer or a member data pointer and an optional list of CXXBaseSpecifiers.
438
/// This list is required to accumulate the pointer-to-member cast history to
439
/// figure out the correct subobject field. In particular, implicit casts grow
440
/// this list and explicit casts like static_cast shrink this list.
441
class PointerToMember : public NonLoc {
442
  friend class ento::SValBuilder;
443
 
444
public:
445
  using PTMDataType =
446
      llvm::PointerUnion<const NamedDecl *, const PointerToMemberData *>;
447
 
448
  const PTMDataType getPTMData() const {
449
    return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
450
  }
451
 
452
  bool isNullMemberPointer() const;
453
 
454
  const NamedDecl *getDecl() const;
455
 
456
  template<typename AdjustedDecl>
457
  const AdjustedDecl *getDeclAs() const {
458
    return dyn_cast_or_null<AdjustedDecl>(getDecl());
459
  }
460
 
461
  using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator;
462
 
463
  iterator begin() const;
464
  iterator end() const;
465
 
466
  static bool classof(SVal V) {
467
    return V.getBaseKind() == NonLocKind &&
468
           V.getSubKind() == PointerToMemberKind;
469
  }
470
 
471
  static bool classof(NonLoc V) {
472
    return V.getSubKind() == PointerToMemberKind;
473
  }
474
 
475
private:
476
  explicit PointerToMember(const PTMDataType D)
477
      : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
478
};
479
 
480
} // namespace nonloc
481
 
482
//==------------------------------------------------------------------------==//
483
//  Subclasses of Loc.
484
//==------------------------------------------------------------------------==//
485
 
486
namespace loc {
487
 
488
class GotoLabel : public Loc {
489
public:
490
  explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) {
491
    assert(Label);
492
  }
493
 
494
  const LabelDecl *getLabel() const {
495
    return static_cast<const LabelDecl *>(Data);
496
  }
497
 
498
  static bool classof(SVal V) {
499
    return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind;
500
  }
501
 
502
  static bool classof(Loc V) { return V.getSubKind() == GotoLabelKind; }
503
};
504
 
505
class MemRegionVal : public Loc {
506
public:
507
  explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {
508
    assert(r);
509
  }
510
 
511
  /// Get the underlining region.
512
  const MemRegion *getRegion() const {
513
    return static_cast<const MemRegion *>(Data);
514
  }
515
 
516
  /// Get the underlining region and strip casts.
517
  const MemRegion* stripCasts(bool StripBaseCasts = true) const;
518
 
519
  template <typename REGION>
520
  const REGION* getRegionAs() const {
521
    return dyn_cast<REGION>(getRegion());
522
  }
523
 
524
  bool operator==(const MemRegionVal &R) const {
525
    return getRegion() == R.getRegion();
526
  }
527
 
528
  bool operator!=(const MemRegionVal &R) const {
529
    return getRegion() != R.getRegion();
530
  }
531
 
532
  static bool classof(SVal V) {
533
    return V.getBaseKind() == LocKind && V.getSubKind() == MemRegionValKind;
534
  }
535
 
536
  static bool classof(Loc V) { return V.getSubKind() == MemRegionValKind; }
537
};
538
 
539
class ConcreteInt : public Loc {
540
public:
541
  explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
542
 
543
  const llvm::APSInt &getValue() const {
544
    return *static_cast<const llvm::APSInt *>(Data);
545
  }
546
 
547
  static bool classof(SVal V) {
548
    return V.getBaseKind() == LocKind && V.getSubKind() == ConcreteIntKind;
549
  }
550
 
551
  static bool classof(Loc V) { return V.getSubKind() == ConcreteIntKind; }
552
};
553
 
554
} // namespace loc
555
} // namespace ento
556
} // namespace clang
557
 
558
namespace llvm {
559
template <typename To, typename From>
560
struct CastInfo<
561
    To, From,
562
    std::enable_if_t<std::is_base_of<::clang::ento::SVal, From>::value>>
563
    : public CastIsPossible<To, ::clang::ento::SVal> {
564
  using Self = CastInfo<
565
      To, From,
566
      std::enable_if_t<std::is_base_of<::clang::ento::SVal, From>::value>>;
567
  static bool isPossible(const From &V) {
568
    return To::classof(*static_cast<const ::clang::ento::SVal *>(&V));
569
  }
570
  static std::optional<To> castFailed() { return std::optional<To>{}; }
571
  static To doCast(const From &f) {
572
    return *static_cast<const To *>(cast<::clang::ento::SVal>(&f));
573
  }
574
  static std::optional<To> doCastIfPossible(const From &f) {
575
    if (!Self::isPossible(f))
576
      return Self::castFailed();
577
    return doCast(f);
578
  }
579
};
580
} // namespace llvm
581
 
582
#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H