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