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