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 SVal(const void * d,bool isLoc,unsigned ValKind)89 explicit SVal(const void *d, bool isLoc, unsigned ValKind) 90 : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} 91 Data(D)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. castAs()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. getAs()103 template <typename T> std::optional<T> getAs() const { 104 return llvm::dyn_cast<T>(*this); 105 } 106 getRawKind()107 unsigned getRawKind() const { return Kind; } getBaseKind()108 BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } getSubKind()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. Profile(llvm::FoldingSetNodeID & ID)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 isUnknown()124 bool isUnknown() const { 125 return getRawKind() == UnknownValKind; 126 } 127 isUndef()128 bool isUndef() const { 129 return getRawKind() == UndefinedValKind; 130 } 131 isUnknownOrUndef()132 bool isUnknownOrUndef() const { 133 return getRawKind() <= UnknownValKind; 134 } 135 isValid()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 symbol_begin()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 symbol_end()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: UndefinedVal()216 UndefinedVal() : SVal(UndefinedValKind) {} classof(SVal V)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 classof(SVal V)227 static bool classof(SVal V) { return !V.isUndef(); } 228 229 protected: DefinedOrUnknownSVal(const void * d,bool isLoc,unsigned ValKind)230 explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind) 231 : SVal(d, isLoc, ValKind) {} SVal(k,D)232 explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr) : SVal(k, D) {} 233 }; 234 235 class UnknownVal : public DefinedOrUnknownSVal { 236 public: UnknownVal()237 explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {} 238 classof(SVal V)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 classof(SVal V)250 static bool classof(SVal V) { return !V.isUnknownOrUndef(); } 251 252 protected: DefinedSVal(const void * d,bool isLoc,unsigned ValKind)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: KnownSVal(const DefinedSVal & V)260 KnownSVal(const DefinedSVal &V) : SVal(V) {} KnownSVal(const UndefinedVal & V)261 KnownSVal(const UndefinedVal &V) : SVal(V) {} classof(SVal V)262 static bool classof(SVal V) { return !V.isUnknown(); } 263 }; 264 265 class NonLoc : public DefinedSVal { 266 protected: NonLoc(unsigned SubKind,const void * d)267 explicit NonLoc(unsigned SubKind, const void *d) 268 : DefinedSVal(d, false, SubKind) {} 269 270 public: 271 void dumpToStream(raw_ostream &Out) const; 272 isCompoundType(QualType T)273 static bool isCompoundType(QualType T) { 274 return T->isArrayType() || T->isRecordType() || 275 T->isAnyComplexType() || T->isVectorType(); 276 } 277 classof(SVal V)278 static bool classof(SVal V) { return V.getBaseKind() == NonLocKind; } 279 }; 280 281 class Loc : public DefinedSVal { 282 protected: Loc(unsigned SubKind,const void * D)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 isLocType(QualType T)289 static bool isLocType(QualType T) { 290 return T->isAnyPointerType() || T->isBlockPointerType() || 291 T->isReferenceType() || T->isNullPtrType(); 292 } 293 classof(SVal V)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; SymbolVal(SymbolRef sym)307 SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) { 308 assert(sym); 309 assert(!Loc::isLocType(sym->getType())); 310 } 311 312 LLVM_ATTRIBUTE_RETURNS_NONNULL getSymbol()313 SymbolRef getSymbol() const { 314 return (const SymExpr *) Data; 315 } 316 isExpression()317 bool isExpression() const { 318 return !isa<SymbolData>(getSymbol()); 319 } 320 classof(SVal V)321 static bool classof(SVal V) { 322 return V.getBaseKind() == NonLocKind && V.getSubKind() == SymbolValKind; 323 } 324 classof(NonLoc V)325 static bool classof(NonLoc V) { return V.getSubKind() == SymbolValKind; } 326 }; 327 328 /// Value representing integer constant. 329 class ConcreteInt : public NonLoc { 330 public: ConcreteInt(const llvm::APSInt & V)331 explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} 332 getValue()333 const llvm::APSInt& getValue() const { 334 return *static_cast<const llvm::APSInt *>(Data); 335 } 336 classof(SVal V)337 static bool classof(SVal V) { 338 return V.getBaseKind() == NonLocKind && V.getSubKind() == ConcreteIntKind; 339 } 340 classof(NonLoc V)341 static bool classof(NonLoc V) { return V.getSubKind() == ConcreteIntKind; } 342 }; 343 344 class LocAsInteger : public NonLoc { 345 friend class ento::SValBuilder; 346 LocAsInteger(const std::pair<SVal,uintptr_t> & data)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: getLoc()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 getNumBits()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 classof(SVal V)369 static bool classof(SVal V) { 370 return V.getBaseKind() == NonLocKind && V.getSubKind() == LocAsIntegerKind; 371 } 372 classof(NonLoc V)373 static bool classof(NonLoc V) { return V.getSubKind() == LocAsIntegerKind; } 374 }; 375 376 class CompoundVal : public NonLoc { 377 friend class ento::SValBuilder; 378 CompoundVal(const CompoundValData * D)379 explicit CompoundVal(const CompoundValData *D) : NonLoc(CompoundValKind, D) { 380 assert(D); 381 } 382 383 public: 384 LLVM_ATTRIBUTE_RETURNS_NONNULL getValue()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 classof(SVal V)394 static bool classof(SVal V) { 395 return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind; 396 } 397 classof(NonLoc V)398 static bool classof(NonLoc V) { return V.getSubKind() == CompoundValKind; } 399 }; 400 401 class LazyCompoundVal : public NonLoc { 402 friend class ento::SValBuilder; 403 LazyCompoundVal(const LazyCompoundValData * D)404 explicit LazyCompoundVal(const LazyCompoundValData *D) 405 : NonLoc(LazyCompoundValKind, D) { 406 assert(D); 407 } 408 409 public: 410 LLVM_ATTRIBUTE_RETURNS_NONNULL getCVData()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 classof(SVal V)421 static bool classof(SVal V) { 422 return V.getBaseKind() == NonLocKind && 423 V.getSubKind() == LazyCompoundValKind; 424 } 425 classof(NonLoc V)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 getPTMData()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> getDeclAs()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 classof(SVal V)466 static bool classof(SVal V) { 467 return V.getBaseKind() == NonLocKind && 468 V.getSubKind() == PointerToMemberKind; 469 } 470 classof(NonLoc V)471 static bool classof(NonLoc V) { 472 return V.getSubKind() == PointerToMemberKind; 473 } 474 475 private: PointerToMember(const PTMDataType D)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: GotoLabel(const LabelDecl * Label)490 explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) { 491 assert(Label); 492 } 493 getLabel()494 const LabelDecl *getLabel() const { 495 return static_cast<const LabelDecl *>(Data); 496 } 497 classof(SVal V)498 static bool classof(SVal V) { 499 return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind; 500 } 501 classof(Loc V)502 static bool classof(Loc V) { return V.getSubKind() == GotoLabelKind; } 503 }; 504 505 class MemRegionVal : public Loc { 506 public: MemRegionVal(const MemRegion * r)507 explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) { 508 assert(r); 509 } 510 511 /// Get the underlining region. getRegion()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> getRegionAs()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 classof(SVal V)532 static bool classof(SVal V) { 533 return V.getBaseKind() == LocKind && V.getSubKind() == MemRegionValKind; 534 } 535 classof(Loc V)536 static bool classof(Loc V) { return V.getSubKind() == MemRegionValKind; } 537 }; 538 539 class ConcreteInt : public Loc { 540 public: ConcreteInt(const llvm::APSInt & V)541 explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} 542 getValue()543 const llvm::APSInt &getValue() const { 544 return *static_cast<const llvm::APSInt *>(Data); 545 } 546 classof(SVal V)547 static bool classof(SVal V) { 548 return V.getBaseKind() == LocKind && V.getSubKind() == ConcreteIntKind; 549 } 550 classof(Loc V)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 583