1 //== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines SVal, Loc, and NonLoc, classes that represent 11 // abstract r-values for use with path-sensitive value tracking. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H 16 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H 17 18 #include "clang/Basic/LLVM.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" 20 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 21 #include "llvm/ADT/ImmutableList.h" 22 23 //==------------------------------------------------------------------------==// 24 // Base SVal types. 25 //==------------------------------------------------------------------------==// 26 27 namespace clang { 28 29 namespace ento { 30 31 class CompoundValData; 32 class LazyCompoundValData; 33 class ProgramState; 34 class BasicValueFactory; 35 class MemRegion; 36 class TypedValueRegion; 37 class MemRegionManager; 38 class ProgramStateManager; 39 class SValBuilder; 40 41 /// SVal - This represents a symbolic expression, which can be either 42 /// an L-value or an R-value. 43 /// 44 class SVal { 45 public: 46 enum BaseKind { 47 // The enumerators must be representable using 2 bits. 48 UndefinedKind = 0, // for subclass UndefinedVal (an uninitialized value) 49 UnknownKind = 1, // for subclass UnknownVal (a void value) 50 LocKind = 2, // for subclass Loc (an L-value) 51 NonLocKind = 3 // for subclass NonLoc (an R-value that's not 52 // an L-value) 53 }; 54 enum { BaseBits = 2, BaseMask = 0x3 }; 55 56 protected: 57 const void *Data; 58 59 /// The lowest 2 bits are a BaseKind (0 -- 3). 60 /// The higher bits are an unsigned "kind" value. 61 unsigned Kind; 62 SVal(const void * d,bool isLoc,unsigned ValKind)63 explicit SVal(const void *d, bool isLoc, unsigned ValKind) 64 : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} 65 66 explicit SVal(BaseKind k, const void *D = nullptr) Data(D)67 : Data(D), Kind(k) {} 68 69 public: SVal()70 explicit SVal() : Data(nullptr), Kind(0) {} 71 72 /// \brief Convert to the specified SVal type, asserting that this SVal is of 73 /// the desired type. 74 template<typename T> castAs()75 T castAs() const { 76 assert(T::isKind(*this)); 77 T t; 78 SVal& sv = t; 79 sv = *this; 80 return t; 81 } 82 83 /// \brief Convert to the specified SVal type, returning None if this SVal is 84 /// not of the desired type. 85 template<typename T> getAs()86 Optional<T> getAs() const { 87 if (!T::isKind(*this)) 88 return None; 89 T t; 90 SVal& sv = t; 91 sv = *this; 92 return t; 93 } 94 95 /// BufferTy - A temporary buffer to hold a set of SVals. 96 typedef SmallVector<SVal,5> BufferTy; 97 getRawKind()98 inline unsigned getRawKind() const { return Kind; } getBaseKind()99 inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } getSubKind()100 inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } 101 102 // This method is required for using SVal in a FoldingSetNode. It 103 // extracts a unique signature for this SVal object. Profile(llvm::FoldingSetNodeID & ID)104 inline void Profile(llvm::FoldingSetNodeID& ID) const { 105 ID.AddInteger((unsigned) getRawKind()); 106 ID.AddPointer(Data); 107 } 108 109 inline bool operator==(const SVal& R) const { 110 return getRawKind() == R.getRawKind() && Data == R.Data; 111 } 112 113 inline bool operator!=(const SVal& R) const { 114 return !(*this == R); 115 } 116 isUnknown()117 inline bool isUnknown() const { 118 return getRawKind() == UnknownKind; 119 } 120 isUndef()121 inline bool isUndef() const { 122 return getRawKind() == UndefinedKind; 123 } 124 isUnknownOrUndef()125 inline bool isUnknownOrUndef() const { 126 return getRawKind() <= UnknownKind; 127 } 128 isValid()129 inline bool isValid() const { 130 return getRawKind() > UnknownKind; 131 } 132 133 bool isConstant() const; 134 135 bool isConstant(int I) const; 136 137 bool isZeroConstant() const; 138 139 /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; 140 bool hasConjuredSymbol() const; 141 142 /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a 143 /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. 144 /// Otherwise return 0. 145 const FunctionDecl *getAsFunctionDecl() const; 146 147 /// \brief If this SVal is a location and wraps a symbol, return that 148 /// SymbolRef. Otherwise return 0. 149 /// 150 /// Casts are ignored during lookup. 151 /// \param IncludeBaseRegions The boolean that controls whether the search 152 /// should continue to the base regions if the region is not symbolic. 153 SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const; 154 155 /// Get the symbol in the SVal or its base region. 156 SymbolRef getLocSymbolInBase() const; 157 158 /// \brief If this SVal wraps a symbol return that SymbolRef. 159 /// Otherwise, return 0. 160 /// 161 /// Casts are ignored during lookup. 162 /// \param IncludeBaseRegions The boolean that controls whether the search 163 /// should continue to the base regions if the region is not symbolic. 164 SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const; 165 166 /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then 167 /// return that expression. Otherwise return NULL. 168 const SymExpr *getAsSymbolicExpression() const; 169 170 const SymExpr* getAsSymExpr() const; 171 172 const MemRegion *getAsRegion() const; 173 174 void dumpToStream(raw_ostream &OS) const; 175 void dump() const; 176 symbol_begin()177 SymExpr::symbol_iterator symbol_begin() const { 178 const SymExpr *SE = getAsSymbolicExpression(); 179 if (SE) 180 return SE->symbol_begin(); 181 else 182 return SymExpr::symbol_iterator(); 183 } 184 symbol_end()185 SymExpr::symbol_iterator symbol_end() const { 186 return SymExpr::symbol_end(); 187 } 188 }; 189 190 191 class UndefinedVal : public SVal { 192 public: UndefinedVal()193 UndefinedVal() : SVal(UndefinedKind) {} 194 195 private: 196 friend class SVal; isKind(const SVal & V)197 static bool isKind(const SVal& V) { 198 return V.getBaseKind() == UndefinedKind; 199 } 200 }; 201 202 class DefinedOrUnknownSVal : public SVal { 203 private: 204 // We want calling these methods to be a compiler error since they are 205 // tautologically false. 206 bool isUndef() const = delete; 207 bool isValid() const = delete; 208 209 protected: DefinedOrUnknownSVal()210 DefinedOrUnknownSVal() {} DefinedOrUnknownSVal(const void * d,bool isLoc,unsigned ValKind)211 explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind) 212 : SVal(d, isLoc, ValKind) {} 213 214 explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr) SVal(k,D)215 : SVal(k, D) {} 216 217 private: 218 friend class SVal; isKind(const SVal & V)219 static bool isKind(const SVal& V) { 220 return !V.isUndef(); 221 } 222 }; 223 224 class UnknownVal : public DefinedOrUnknownSVal { 225 public: UnknownVal()226 explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} 227 228 private: 229 friend class SVal; isKind(const SVal & V)230 static bool isKind(const SVal &V) { 231 return V.getBaseKind() == UnknownKind; 232 } 233 }; 234 235 class DefinedSVal : public DefinedOrUnknownSVal { 236 private: 237 // We want calling these methods to be a compiler error since they are 238 // tautologically true/false. 239 bool isUnknown() const = delete; 240 bool isUnknownOrUndef() const = delete; 241 bool isValid() const = delete; 242 protected: DefinedSVal()243 DefinedSVal() {} DefinedSVal(const void * d,bool isLoc,unsigned ValKind)244 explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind) 245 : DefinedOrUnknownSVal(d, isLoc, ValKind) {} 246 private: 247 friend class SVal; isKind(const SVal & V)248 static bool isKind(const SVal& V) { 249 return !V.isUnknownOrUndef(); 250 } 251 }; 252 253 254 /// \brief Represents an SVal that is guaranteed to not be UnknownVal. 255 class KnownSVal : public SVal { KnownSVal()256 KnownSVal() {} 257 friend class SVal; isKind(const SVal & V)258 static bool isKind(const SVal &V) { 259 return !V.isUnknown(); 260 } 261 public: KnownSVal(const DefinedSVal & V)262 KnownSVal(const DefinedSVal &V) : SVal(V) {} KnownSVal(const UndefinedVal & V)263 KnownSVal(const UndefinedVal &V) : SVal(V) {} 264 }; 265 266 class NonLoc : public DefinedSVal { 267 protected: NonLoc()268 NonLoc() {} NonLoc(unsigned SubKind,const void * d)269 explicit NonLoc(unsigned SubKind, const void *d) 270 : DefinedSVal(d, false, SubKind) {} 271 272 public: 273 void dumpToStream(raw_ostream &Out) const; 274 275 private: 276 friend class SVal; isKind(const SVal & V)277 static bool isKind(const SVal& V) { 278 return V.getBaseKind() == NonLocKind; 279 } 280 }; 281 282 class Loc : public DefinedSVal { 283 protected: Loc()284 Loc() {} Loc(unsigned SubKind,const void * D)285 explicit Loc(unsigned SubKind, const void *D) 286 : DefinedSVal(const_cast<void*>(D), true, SubKind) {} 287 288 public: 289 void dumpToStream(raw_ostream &Out) const; 290 isLocType(QualType T)291 static inline bool isLocType(QualType T) { 292 return T->isAnyPointerType() || T->isBlockPointerType() || 293 T->isReferenceType() || T->isNullPtrType(); 294 } 295 296 private: 297 friend class SVal; isKind(const SVal & V)298 static bool isKind(const SVal& V) { 299 return V.getBaseKind() == LocKind; 300 } 301 }; 302 303 //==------------------------------------------------------------------------==// 304 // Subclasses of NonLoc. 305 //==------------------------------------------------------------------------==// 306 307 namespace nonloc { 308 309 enum Kind { ConcreteIntKind, SymbolValKind, 310 LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; 311 312 /// \brief Represents symbolic expression. 313 class SymbolVal : public NonLoc { 314 public: SymbolVal(SymbolRef sym)315 SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} 316 getSymbol()317 SymbolRef getSymbol() const { 318 return (const SymExpr*) Data; 319 } 320 isExpression()321 bool isExpression() const { 322 return !isa<SymbolData>(getSymbol()); 323 } 324 325 private: 326 friend class SVal; SymbolVal()327 SymbolVal() {} isKind(const SVal & V)328 static bool isKind(const SVal& V) { 329 return V.getBaseKind() == NonLocKind && 330 V.getSubKind() == SymbolValKind; 331 } 332 isKind(const NonLoc & V)333 static bool isKind(const NonLoc& V) { 334 return V.getSubKind() == SymbolValKind; 335 } 336 }; 337 338 /// \brief Value representing integer constant. 339 class ConcreteInt : public NonLoc { 340 public: ConcreteInt(const llvm::APSInt & V)341 explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} 342 getValue()343 const llvm::APSInt& getValue() const { 344 return *static_cast<const llvm::APSInt*>(Data); 345 } 346 347 // Transfer functions for binary/unary operations on ConcreteInts. 348 SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op, 349 const ConcreteInt& R) const; 350 351 ConcreteInt evalComplement(SValBuilder &svalBuilder) const; 352 353 ConcreteInt evalMinus(SValBuilder &svalBuilder) const; 354 355 private: 356 friend class SVal; ConcreteInt()357 ConcreteInt() {} isKind(const SVal & V)358 static bool isKind(const SVal& V) { 359 return V.getBaseKind() == NonLocKind && 360 V.getSubKind() == ConcreteIntKind; 361 } 362 isKind(const NonLoc & V)363 static bool isKind(const NonLoc& V) { 364 return V.getSubKind() == ConcreteIntKind; 365 } 366 }; 367 368 class LocAsInteger : public NonLoc { 369 friend class ento::SValBuilder; 370 LocAsInteger(const std::pair<SVal,uintptr_t> & data)371 explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data) 372 : NonLoc(LocAsIntegerKind, &data) { 373 assert (data.first.getAs<Loc>()); 374 } 375 376 public: 377 getLoc()378 Loc getLoc() const { 379 const std::pair<SVal, uintptr_t> *D = 380 static_cast<const std::pair<SVal, uintptr_t> *>(Data); 381 return D->first.castAs<Loc>(); 382 } 383 getPersistentLoc()384 Loc getPersistentLoc() const { 385 const std::pair<SVal, uintptr_t> *D = 386 static_cast<const std::pair<SVal, uintptr_t> *>(Data); 387 const SVal& V = D->first; 388 return V.castAs<Loc>(); 389 } 390 getNumBits()391 unsigned getNumBits() const { 392 const std::pair<SVal, uintptr_t> *D = 393 static_cast<const std::pair<SVal, uintptr_t> *>(Data); 394 return D->second; 395 } 396 397 private: 398 friend class SVal; LocAsInteger()399 LocAsInteger() {} isKind(const SVal & V)400 static bool isKind(const SVal& V) { 401 return V.getBaseKind() == NonLocKind && 402 V.getSubKind() == LocAsIntegerKind; 403 } 404 isKind(const NonLoc & V)405 static bool isKind(const NonLoc& V) { 406 return V.getSubKind() == LocAsIntegerKind; 407 } 408 }; 409 410 class CompoundVal : public NonLoc { 411 friend class ento::SValBuilder; 412 CompoundVal(const CompoundValData * D)413 explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} 414 415 public: getValue()416 const CompoundValData* getValue() const { 417 return static_cast<const CompoundValData*>(Data); 418 } 419 420 typedef llvm::ImmutableList<SVal>::iterator iterator; 421 iterator begin() const; 422 iterator end() const; 423 424 private: 425 friend class SVal; CompoundVal()426 CompoundVal() {} isKind(const SVal & V)427 static bool isKind(const SVal& V) { 428 return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind; 429 } 430 isKind(const NonLoc & V)431 static bool isKind(const NonLoc& V) { 432 return V.getSubKind() == CompoundValKind; 433 } 434 }; 435 436 class LazyCompoundVal : public NonLoc { 437 friend class ento::SValBuilder; 438 LazyCompoundVal(const LazyCompoundValData * D)439 explicit LazyCompoundVal(const LazyCompoundValData *D) 440 : NonLoc(LazyCompoundValKind, D) {} 441 public: getCVData()442 const LazyCompoundValData *getCVData() const { 443 return static_cast<const LazyCompoundValData*>(Data); 444 } 445 const void *getStore() const; 446 const TypedValueRegion *getRegion() const; 447 448 private: 449 friend class SVal; LazyCompoundVal()450 LazyCompoundVal() {} isKind(const SVal & V)451 static bool isKind(const SVal& V) { 452 return V.getBaseKind() == NonLocKind && 453 V.getSubKind() == LazyCompoundValKind; 454 } isKind(const NonLoc & V)455 static bool isKind(const NonLoc& V) { 456 return V.getSubKind() == LazyCompoundValKind; 457 } 458 }; 459 460 } // end namespace ento::nonloc 461 462 //==------------------------------------------------------------------------==// 463 // Subclasses of Loc. 464 //==------------------------------------------------------------------------==// 465 466 namespace loc { 467 468 enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind }; 469 470 class GotoLabel : public Loc { 471 public: GotoLabel(LabelDecl * Label)472 explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {} 473 getLabel()474 const LabelDecl *getLabel() const { 475 return static_cast<const LabelDecl*>(Data); 476 } 477 478 private: 479 friend class SVal; GotoLabel()480 GotoLabel() {} isKind(const SVal & V)481 static bool isKind(const SVal& V) { 482 return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind; 483 } 484 isKind(const Loc & V)485 static bool isKind(const Loc& V) { 486 return V.getSubKind() == GotoLabelKind; 487 } 488 }; 489 490 491 class MemRegionVal : public Loc { 492 public: MemRegionVal(const MemRegion * r)493 explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} 494 495 /// \brief Get the underlining region. getRegion()496 const MemRegion* getRegion() const { 497 return static_cast<const MemRegion*>(Data); 498 } 499 500 /// \brief Get the underlining region and strip casts. 501 const MemRegion* stripCasts(bool StripBaseCasts = true) const; 502 503 template <typename REGION> getRegionAs()504 const REGION* getRegionAs() const { 505 return dyn_cast<REGION>(getRegion()); 506 } 507 508 inline bool operator==(const MemRegionVal& R) const { 509 return getRegion() == R.getRegion(); 510 } 511 512 inline bool operator!=(const MemRegionVal& R) const { 513 return getRegion() != R.getRegion(); 514 } 515 516 private: 517 friend class SVal; MemRegionVal()518 MemRegionVal() {} isKind(const SVal & V)519 static bool isKind(const SVal& V) { 520 return V.getBaseKind() == LocKind && 521 V.getSubKind() == MemRegionKind; 522 } 523 isKind(const Loc & V)524 static bool isKind(const Loc& V) { 525 return V.getSubKind() == MemRegionKind; 526 } 527 }; 528 529 class ConcreteInt : public Loc { 530 public: ConcreteInt(const llvm::APSInt & V)531 explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} 532 getValue()533 const llvm::APSInt& getValue() const { 534 return *static_cast<const llvm::APSInt*>(Data); 535 } 536 537 // Transfer functions for binary/unary operations on ConcreteInts. 538 SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, 539 const ConcreteInt& R) const; 540 541 private: 542 friend class SVal; ConcreteInt()543 ConcreteInt() {} isKind(const SVal & V)544 static bool isKind(const SVal& V) { 545 return V.getBaseKind() == LocKind && 546 V.getSubKind() == ConcreteIntKind; 547 } 548 isKind(const Loc & V)549 static bool isKind(const Loc& V) { 550 return V.getSubKind() == ConcreteIntKind; 551 } 552 }; 553 554 } // end ento::loc namespace 555 556 } // end ento namespace 557 558 } // end clang namespace 559 560 namespace llvm { 561 static inline raw_ostream &operator<<(raw_ostream &os, 562 clang::ento::SVal V) { 563 V.dumpToStream(os); 564 return os; 565 } 566 567 template <typename T> struct isPodLike; 568 template <> struct isPodLike<clang::ento::SVal> { 569 static const bool value = true; 570 }; 571 572 } // end llvm namespace 573 574 #endif 575