File indexing completed on 2026-05-10 08:37:09
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
0015 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
0016
0017 #include "clang/AST/Expr.h"
0018 #include "clang/AST/Type.h"
0019 #include "clang/Basic/LLVM.h"
0020 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h"
0021 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
0022 #include "llvm/ADT/APSInt.h"
0023 #include "llvm/ADT/FoldingSet.h"
0024 #include "llvm/ADT/ImmutableList.h"
0025 #include "llvm/ADT/PointerUnion.h"
0026 #include "llvm/ADT/STLForwardCompat.h"
0027 #include "llvm/ADT/iterator_range.h"
0028 #include "llvm/Support/Casting.h"
0029 #include <cassert>
0030 #include <cstdint>
0031 #include <optional>
0032 #include <utility>
0033
0034
0035
0036
0037
0038 namespace clang {
0039
0040 class CXXBaseSpecifier;
0041 class FunctionDecl;
0042 class LabelDecl;
0043
0044 namespace ento {
0045
0046 class CompoundValData;
0047 class LazyCompoundValData;
0048 class MemRegion;
0049 class PointerToMemberData;
0050 class SValBuilder;
0051 class TypedValueRegion;
0052
0053
0054
0055
0056 class SVal {
0057 public:
0058 enum SValKind : unsigned char {
0059 #define BASIC_SVAL(Id, Parent) Id##Kind,
0060 #define LOC_SVAL(Id, Parent) Loc##Id##Kind,
0061 #define NONLOC_SVAL(Id, Parent) NonLoc##Id##Kind,
0062 #define SVAL_RANGE(Id, First, Last) \
0063 BEGIN_##Id = Id##First##Kind, END_##Id = Id##Last##Kind,
0064 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
0065 };
0066
0067 protected:
0068 const void *Data = nullptr;
0069 SValKind Kind = UndefinedValKind;
0070
0071 explicit SVal(SValKind Kind, const void *Data = nullptr)
0072 : Data(Data), Kind(Kind) {}
0073
0074 template <typename T> const T *castDataAs() const {
0075 return static_cast<const T *>(Data);
0076 }
0077
0078 public:
0079 explicit SVal() = default;
0080
0081
0082
0083 template <typename T> T castAs() const { return llvm::cast<T>(*this); }
0084
0085
0086
0087 template <typename T> std::optional<T> getAs() const {
0088 return llvm::dyn_cast<T>(*this);
0089 }
0090
0091 SValKind getKind() const { return Kind; }
0092
0093 StringRef getKindStr() const;
0094
0095
0096
0097 void Profile(llvm::FoldingSetNodeID &ID) const {
0098 ID.AddPointer(Data);
0099 ID.AddInteger(llvm::to_underlying(getKind()));
0100 }
0101
0102 bool operator==(SVal R) const { return Kind == R.Kind && Data == R.Data; }
0103 bool operator!=(SVal R) const { return !(*this == R); }
0104
0105 bool isUnknown() const { return getKind() == UnknownValKind; }
0106
0107 bool isUndef() const { return getKind() == UndefinedValKind; }
0108
0109 bool isUnknownOrUndef() const { return isUnknown() || isUndef(); }
0110
0111 bool isValid() const { return !isUnknownOrUndef(); }
0112
0113 bool isConstant() const;
0114
0115 bool isConstant(int I) const;
0116
0117 bool isZeroConstant() const;
0118
0119
0120
0121
0122 const FunctionDecl *getAsFunctionDecl() const;
0123
0124
0125
0126
0127
0128
0129
0130 SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const;
0131
0132
0133 SymbolRef getLocSymbolInBase() const;
0134
0135
0136
0137
0138
0139
0140
0141 SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const;
0142
0143
0144
0145
0146 const llvm::APSInt *getAsInteger() const;
0147
0148 const MemRegion *getAsRegion() const;
0149
0150
0151 void printJson(raw_ostream &Out, bool AddQuotes) const;
0152
0153 void dumpToStream(raw_ostream &OS) const;
0154 void dump() const;
0155
0156 llvm::iterator_range<SymExpr::symbol_iterator> symbols() const {
0157 if (const SymExpr *SE = getAsSymbol(true))
0158 return SE->symbols();
0159 SymExpr::symbol_iterator end{};
0160 return llvm::make_range(end, end);
0161 }
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174 QualType getType(const ASTContext &) const;
0175 };
0176
0177 inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) {
0178 V.dumpToStream(os);
0179 return os;
0180 }
0181
0182 namespace nonloc {
0183
0184 #define NONLOC_SVAL(Id, Parent) \
0185 inline constexpr auto Id##Kind = SVal::SValKind::NonLoc##Id##Kind;
0186 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
0187 }
0188
0189 namespace loc {
0190
0191 #define LOC_SVAL(Id, Parent) \
0192 inline constexpr auto Id##Kind = SVal::SValKind::Loc##Id##Kind;
0193 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
0194 }
0195
0196 class UndefinedVal : public SVal {
0197 public:
0198 UndefinedVal() : SVal(UndefinedValKind) {}
0199 static bool classof(SVal V) { return V.getKind() == UndefinedValKind; }
0200 };
0201
0202 class DefinedOrUnknownSVal : public SVal {
0203 public:
0204
0205
0206 bool isUndef() const = delete;
0207 bool isValid() const = delete;
0208
0209 static bool classof(SVal V) { return !V.isUndef(); }
0210
0211 protected:
0212 explicit DefinedOrUnknownSVal(SValKind Kind, const void *Data = nullptr)
0213 : SVal(Kind, Data) {}
0214 };
0215
0216 class UnknownVal : public DefinedOrUnknownSVal {
0217 public:
0218 explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {}
0219
0220 static bool classof(SVal V) { return V.getKind() == UnknownValKind; }
0221 };
0222
0223 class DefinedSVal : public DefinedOrUnknownSVal {
0224 public:
0225
0226
0227 bool isUnknown() const = delete;
0228 bool isUnknownOrUndef() const = delete;
0229 bool isValid() const = delete;
0230
0231 static bool classof(SVal V) { return !V.isUnknownOrUndef(); }
0232
0233 protected:
0234 explicit DefinedSVal(SValKind Kind, const void *Data)
0235 : DefinedOrUnknownSVal(Kind, Data) {}
0236 };
0237
0238 class NonLoc : public DefinedSVal {
0239 protected:
0240 NonLoc(SValKind Kind, const void *Data) : DefinedSVal(Kind, Data) {}
0241
0242 public:
0243 void dumpToStream(raw_ostream &Out) const;
0244
0245 static bool isCompoundType(QualType T) {
0246 return T->isArrayType() || T->isRecordType() ||
0247 T->isAnyComplexType() || T->isVectorType();
0248 }
0249
0250 static bool classof(SVal V) {
0251 return BEGIN_NonLoc <= V.getKind() && V.getKind() <= END_NonLoc;
0252 }
0253 };
0254
0255 class Loc : public DefinedSVal {
0256 protected:
0257 Loc(SValKind Kind, const void *Data) : DefinedSVal(Kind, Data) {}
0258
0259 public:
0260 void dumpToStream(raw_ostream &Out) const;
0261
0262 static bool isLocType(QualType T) {
0263 return T->isAnyPointerType() || T->isBlockPointerType() ||
0264 T->isReferenceType() || T->isNullPtrType();
0265 }
0266
0267 static bool classof(SVal V) {
0268 return BEGIN_Loc <= V.getKind() && V.getKind() <= END_Loc;
0269 }
0270 };
0271
0272
0273
0274
0275
0276 namespace nonloc {
0277
0278
0279 class SymbolVal : public NonLoc {
0280 public:
0281 SymbolVal() = delete;
0282 explicit SymbolVal(SymbolRef Sym) : NonLoc(SymbolValKind, Sym) {
0283 assert(Sym);
0284 assert(!Loc::isLocType(Sym->getType()));
0285 }
0286
0287 LLVM_ATTRIBUTE_RETURNS_NONNULL
0288 SymbolRef getSymbol() const {
0289 return (const SymExpr *) Data;
0290 }
0291
0292 bool isExpression() const {
0293 return !isa<SymbolData>(getSymbol());
0294 }
0295
0296 static bool classof(SVal V) { return V.getKind() == SymbolValKind; }
0297 };
0298
0299
0300 class ConcreteInt : public NonLoc {
0301 public:
0302 explicit ConcreteInt(APSIntPtr V) : NonLoc(ConcreteIntKind, V.get()) {}
0303
0304 APSIntPtr getValue() const {
0305
0306 return APSIntPtr::unsafeConstructor(castDataAs<llvm::APSInt>());
0307 }
0308
0309 static bool classof(SVal V) { return V.getKind() == ConcreteIntKind; }
0310 };
0311
0312 class LocAsInteger : public NonLoc {
0313 friend class ento::SValBuilder;
0314
0315 explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data)
0316 : NonLoc(LocAsIntegerKind, &data) {
0317
0318
0319 [[maybe_unused]] SValKind K = data.first.getKind();
0320 assert(K == loc::MemRegionValKind || K == loc::GotoLabelKind);
0321 }
0322
0323 public:
0324 Loc getLoc() const {
0325 return castDataAs<std::pair<SVal, uintptr_t>>()->first.castAs<Loc>();
0326 }
0327
0328 unsigned getNumBits() const {
0329 return castDataAs<std::pair<SVal, uintptr_t>>()->second;
0330 }
0331
0332 static bool classof(SVal V) { return V.getKind() == LocAsIntegerKind; }
0333 };
0334
0335
0336
0337
0338
0339 class CompoundVal : public NonLoc {
0340 friend class ento::SValBuilder;
0341
0342 explicit CompoundVal(const CompoundValData *D) : NonLoc(CompoundValKind, D) {
0343 assert(D);
0344 }
0345
0346 public:
0347 LLVM_ATTRIBUTE_RETURNS_NONNULL
0348 const CompoundValData* getValue() const {
0349 return castDataAs<CompoundValData>();
0350 }
0351
0352 using iterator = llvm::ImmutableList<SVal>::iterator;
0353 iterator begin() const;
0354 iterator end() const;
0355
0356 static bool classof(SVal V) { return V.getKind() == CompoundValKind; }
0357 };
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389 class LazyCompoundVal : public NonLoc {
0390 friend class ento::SValBuilder;
0391
0392 explicit LazyCompoundVal(const LazyCompoundValData *D)
0393 : NonLoc(LazyCompoundValKind, D) {
0394 assert(D);
0395 }
0396
0397 public:
0398 LLVM_ATTRIBUTE_RETURNS_NONNULL
0399 const LazyCompoundValData *getCVData() const {
0400 return castDataAs<LazyCompoundValData>();
0401 }
0402
0403
0404 const void *getStore() const;
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418 LLVM_ATTRIBUTE_RETURNS_NONNULL
0419 const TypedValueRegion *getRegion() const;
0420
0421 static bool classof(SVal V) { return V.getKind() == LazyCompoundValKind; }
0422 };
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434 class PointerToMember : public NonLoc {
0435 friend class ento::SValBuilder;
0436
0437 public:
0438 using PTMDataType =
0439 llvm::PointerUnion<const NamedDecl *, const PointerToMemberData *>;
0440
0441 const PTMDataType getPTMData() const {
0442 return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
0443 }
0444
0445 bool isNullMemberPointer() const;
0446
0447 const NamedDecl *getDecl() const;
0448
0449 template<typename AdjustedDecl>
0450 const AdjustedDecl *getDeclAs() const {
0451 return dyn_cast_or_null<AdjustedDecl>(getDecl());
0452 }
0453
0454 using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator;
0455
0456 iterator begin() const;
0457 iterator end() const;
0458
0459 static bool classof(SVal V) { return V.getKind() == PointerToMemberKind; }
0460
0461 private:
0462 explicit PointerToMember(const PTMDataType D)
0463 : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
0464 };
0465
0466 }
0467
0468
0469
0470
0471
0472 namespace loc {
0473
0474 class GotoLabel : public Loc {
0475 public:
0476 explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) {
0477 assert(Label);
0478 }
0479
0480 const LabelDecl *getLabel() const { return castDataAs<LabelDecl>(); }
0481
0482 static bool classof(SVal V) { return V.getKind() == GotoLabelKind; }
0483 };
0484
0485 class MemRegionVal : public Loc {
0486 public:
0487 explicit MemRegionVal(const MemRegion *r) : Loc(MemRegionValKind, r) {
0488 assert(r);
0489 }
0490
0491
0492 LLVM_ATTRIBUTE_RETURNS_NONNULL
0493 const MemRegion *getRegion() const { return castDataAs<MemRegion>(); }
0494
0495
0496 LLVM_ATTRIBUTE_RETURNS_NONNULL
0497 const MemRegion* stripCasts(bool StripBaseCasts = true) const;
0498
0499 template <typename REGION>
0500 const REGION* getRegionAs() const {
0501 return dyn_cast<REGION>(getRegion());
0502 }
0503
0504 bool operator==(const MemRegionVal &R) const {
0505 return getRegion() == R.getRegion();
0506 }
0507
0508 bool operator!=(const MemRegionVal &R) const {
0509 return getRegion() != R.getRegion();
0510 }
0511
0512 static bool classof(SVal V) { return V.getKind() == MemRegionValKind; }
0513 };
0514
0515 class ConcreteInt : public Loc {
0516 public:
0517 explicit ConcreteInt(APSIntPtr V) : Loc(ConcreteIntKind, V.get()) {}
0518
0519 APSIntPtr getValue() const {
0520
0521 return APSIntPtr::unsafeConstructor(castDataAs<llvm::APSInt>());
0522 }
0523
0524 static bool classof(SVal V) { return V.getKind() == ConcreteIntKind; }
0525 };
0526
0527 }
0528 }
0529 }
0530
0531 namespace llvm {
0532 template <typename To, typename From>
0533 struct CastInfo<
0534 To, From,
0535 std::enable_if_t<std::is_base_of<::clang::ento::SVal, From>::value>>
0536 : public CastIsPossible<To, ::clang::ento::SVal> {
0537 using Self = CastInfo<
0538 To, From,
0539 std::enable_if_t<std::is_base_of<::clang::ento::SVal, From>::value>>;
0540 static bool isPossible(const From &V) {
0541 return To::classof(*static_cast<const ::clang::ento::SVal *>(&V));
0542 }
0543 static std::optional<To> castFailed() { return std::optional<To>{}; }
0544 static To doCast(const From &f) {
0545 return *static_cast<const To *>(cast<::clang::ento::SVal>(&f));
0546 }
0547 static std::optional<To> doCastIfPossible(const From &f) {
0548 if (!Self::isPossible(f))
0549 return Self::castFailed();
0550 return doCast(f);
0551 }
0552 };
0553 }
0554
0555 #endif