1 //== SymbolManager.h - Management of Symbolic Values ------------*- 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 SymbolManager, a class that manages symbolic values 11 // created for use by ExprEngine and related classes. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_GR_SYMMGR_H 16 #define LLVM_CLANG_GR_SYMMGR_H 17 18 #include "clang/AST/Decl.h" 19 #include "clang/AST/Expr.h" 20 #include "clang/Analysis/AnalysisContext.h" 21 #include "llvm/Support/DataTypes.h" 22 #include "llvm/ADT/FoldingSet.h" 23 #include "llvm/ADT/DenseSet.h" 24 25 namespace llvm { 26 class BumpPtrAllocator; 27 class raw_ostream; 28 } 29 30 namespace clang { 31 class ASTContext; 32 class StackFrameContext; 33 34 namespace ento { 35 class BasicValueFactory; 36 class MemRegion; 37 class SubRegion; 38 class TypedRegion; 39 class VarRegion; 40 41 class SymExpr : public llvm::FoldingSetNode { 42 public: 43 enum Kind { BEGIN_SYMBOLS, 44 RegionValueKind, ConjuredKind, DerivedKind, ExtentKind, 45 MetadataKind, 46 END_SYMBOLS, 47 SymIntKind, SymSymKind }; 48 private: 49 Kind K; 50 51 protected: SymExpr(Kind k)52 SymExpr(Kind k) : K(k) {} 53 54 public: ~SymExpr()55 virtual ~SymExpr() {} 56 getKind()57 Kind getKind() const { return K; } 58 59 void dump() const; 60 61 virtual void dumpToStream(llvm::raw_ostream &os) const = 0; 62 63 virtual QualType getType(ASTContext&) const = 0; 64 virtual void Profile(llvm::FoldingSetNodeID& profile) = 0; 65 66 // Implement isa<T> support. classof(const SymExpr *)67 static inline bool classof(const SymExpr*) { return true; } 68 }; 69 70 typedef unsigned SymbolID; 71 72 class SymbolData : public SymExpr { 73 private: 74 const SymbolID Sym; 75 76 protected: SymbolData(Kind k,SymbolID sym)77 SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} 78 79 public: ~SymbolData()80 virtual ~SymbolData() {} 81 getSymbolID()82 SymbolID getSymbolID() const { return Sym; } 83 84 // Implement isa<T> support. classof(const SymExpr * SE)85 static inline bool classof(const SymExpr* SE) { 86 Kind k = SE->getKind(); 87 return k > BEGIN_SYMBOLS && k < END_SYMBOLS; 88 } 89 }; 90 91 typedef const SymbolData* SymbolRef; 92 93 // A symbol representing the value of a MemRegion. 94 class SymbolRegionValue : public SymbolData { 95 const TypedRegion *R; 96 97 public: SymbolRegionValue(SymbolID sym,const TypedRegion * r)98 SymbolRegionValue(SymbolID sym, const TypedRegion *r) 99 : SymbolData(RegionValueKind, sym), R(r) {} 100 getRegion()101 const TypedRegion* getRegion() const { return R; } 102 Profile(llvm::FoldingSetNodeID & profile,const TypedRegion * R)103 static void Profile(llvm::FoldingSetNodeID& profile, const TypedRegion* R) { 104 profile.AddInteger((unsigned) RegionValueKind); 105 profile.AddPointer(R); 106 } 107 Profile(llvm::FoldingSetNodeID & profile)108 virtual void Profile(llvm::FoldingSetNodeID& profile) { 109 Profile(profile, R); 110 } 111 112 void dumpToStream(llvm::raw_ostream &os) const; 113 114 QualType getType(ASTContext&) const; 115 116 // Implement isa<T> support. classof(const SymExpr * SE)117 static inline bool classof(const SymExpr* SE) { 118 return SE->getKind() == RegionValueKind; 119 } 120 }; 121 122 // A symbol representing the result of an expression. 123 class SymbolConjured : public SymbolData { 124 const Stmt* S; 125 QualType T; 126 unsigned Count; 127 const void* SymbolTag; 128 129 public: SymbolConjured(SymbolID sym,const Stmt * s,QualType t,unsigned count,const void * symbolTag)130 SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count, 131 const void* symbolTag) 132 : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count), 133 SymbolTag(symbolTag) {} 134 getStmt()135 const Stmt* getStmt() const { return S; } getCount()136 unsigned getCount() const { return Count; } getTag()137 const void* getTag() const { return SymbolTag; } 138 139 QualType getType(ASTContext&) const; 140 141 void dumpToStream(llvm::raw_ostream &os) const; 142 Profile(llvm::FoldingSetNodeID & profile,const Stmt * S,QualType T,unsigned Count,const void * SymbolTag)143 static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S, 144 QualType T, unsigned Count, const void* SymbolTag) { 145 profile.AddInteger((unsigned) ConjuredKind); 146 profile.AddPointer(S); 147 profile.Add(T); 148 profile.AddInteger(Count); 149 profile.AddPointer(SymbolTag); 150 } 151 Profile(llvm::FoldingSetNodeID & profile)152 virtual void Profile(llvm::FoldingSetNodeID& profile) { 153 Profile(profile, S, T, Count, SymbolTag); 154 } 155 156 // Implement isa<T> support. classof(const SymExpr * SE)157 static inline bool classof(const SymExpr* SE) { 158 return SE->getKind() == ConjuredKind; 159 } 160 }; 161 162 // A symbol representing the value of a MemRegion whose parent region has 163 // symbolic value. 164 class SymbolDerived : public SymbolData { 165 SymbolRef parentSymbol; 166 const TypedRegion *R; 167 168 public: SymbolDerived(SymbolID sym,SymbolRef parent,const TypedRegion * r)169 SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r) 170 : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {} 171 getParentSymbol()172 SymbolRef getParentSymbol() const { return parentSymbol; } getRegion()173 const TypedRegion *getRegion() const { return R; } 174 175 QualType getType(ASTContext&) const; 176 177 void dumpToStream(llvm::raw_ostream &os) const; 178 Profile(llvm::FoldingSetNodeID & profile,SymbolRef parent,const TypedRegion * r)179 static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent, 180 const TypedRegion *r) { 181 profile.AddInteger((unsigned) DerivedKind); 182 profile.AddPointer(r); 183 profile.AddPointer(parent); 184 } 185 Profile(llvm::FoldingSetNodeID & profile)186 virtual void Profile(llvm::FoldingSetNodeID& profile) { 187 Profile(profile, parentSymbol, R); 188 } 189 190 // Implement isa<T> support. classof(const SymExpr * SE)191 static inline bool classof(const SymExpr* SE) { 192 return SE->getKind() == DerivedKind; 193 } 194 }; 195 196 /// SymbolExtent - Represents the extent (size in bytes) of a bounded region. 197 /// Clients should not ask the SymbolManager for a region's extent. Always use 198 /// SubRegion::getExtent instead -- the value returned may not be a symbol. 199 class SymbolExtent : public SymbolData { 200 const SubRegion *R; 201 202 public: SymbolExtent(SymbolID sym,const SubRegion * r)203 SymbolExtent(SymbolID sym, const SubRegion *r) 204 : SymbolData(ExtentKind, sym), R(r) {} 205 getRegion()206 const SubRegion *getRegion() const { return R; } 207 208 QualType getType(ASTContext&) const; 209 210 void dumpToStream(llvm::raw_ostream &os) const; 211 Profile(llvm::FoldingSetNodeID & profile,const SubRegion * R)212 static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) { 213 profile.AddInteger((unsigned) ExtentKind); 214 profile.AddPointer(R); 215 } 216 Profile(llvm::FoldingSetNodeID & profile)217 virtual void Profile(llvm::FoldingSetNodeID& profile) { 218 Profile(profile, R); 219 } 220 221 // Implement isa<T> support. classof(const SymExpr * SE)222 static inline bool classof(const SymExpr* SE) { 223 return SE->getKind() == ExtentKind; 224 } 225 }; 226 227 /// SymbolMetadata - Represents path-dependent metadata about a specific region. 228 /// Metadata symbols remain live as long as they are marked as in use before 229 /// dead-symbol sweeping AND their associated regions are still alive. 230 /// Intended for use by checkers. 231 class SymbolMetadata : public SymbolData { 232 const MemRegion* R; 233 const Stmt* S; 234 QualType T; 235 unsigned Count; 236 const void* Tag; 237 public: SymbolMetadata(SymbolID sym,const MemRegion * r,const Stmt * s,QualType t,unsigned count,const void * tag)238 SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt* s, QualType t, 239 unsigned count, const void* tag) 240 : SymbolData(MetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {} 241 getRegion()242 const MemRegion *getRegion() const { return R; } getStmt()243 const Stmt* getStmt() const { return S; } getCount()244 unsigned getCount() const { return Count; } getTag()245 const void* getTag() const { return Tag; } 246 247 QualType getType(ASTContext&) const; 248 249 void dumpToStream(llvm::raw_ostream &os) const; 250 Profile(llvm::FoldingSetNodeID & profile,const MemRegion * R,const Stmt * S,QualType T,unsigned Count,const void * Tag)251 static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R, 252 const Stmt *S, QualType T, unsigned Count, 253 const void *Tag) { 254 profile.AddInteger((unsigned) MetadataKind); 255 profile.AddPointer(R); 256 profile.AddPointer(S); 257 profile.Add(T); 258 profile.AddInteger(Count); 259 profile.AddPointer(Tag); 260 } 261 Profile(llvm::FoldingSetNodeID & profile)262 virtual void Profile(llvm::FoldingSetNodeID& profile) { 263 Profile(profile, R, S, T, Count, Tag); 264 } 265 266 // Implement isa<T> support. classof(const SymExpr * SE)267 static inline bool classof(const SymExpr* SE) { 268 return SE->getKind() == MetadataKind; 269 } 270 }; 271 272 // SymIntExpr - Represents symbolic expression like 'x' + 3. 273 class SymIntExpr : public SymExpr { 274 const SymExpr *LHS; 275 BinaryOperator::Opcode Op; 276 const llvm::APSInt& RHS; 277 QualType T; 278 279 public: SymIntExpr(const SymExpr * lhs,BinaryOperator::Opcode op,const llvm::APSInt & rhs,QualType t)280 SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, 281 const llvm::APSInt& rhs, QualType t) 282 : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} 283 284 // FIXME: We probably need to make this out-of-line to avoid redundant 285 // generation of virtual functions. getType(ASTContext & C)286 QualType getType(ASTContext& C) const { return T; } 287 getOpcode()288 BinaryOperator::Opcode getOpcode() const { return Op; } 289 290 void dumpToStream(llvm::raw_ostream &os) const; 291 getLHS()292 const SymExpr *getLHS() const { return LHS; } getRHS()293 const llvm::APSInt &getRHS() const { return RHS; } 294 Profile(llvm::FoldingSetNodeID & ID,const SymExpr * lhs,BinaryOperator::Opcode op,const llvm::APSInt & rhs,QualType t)295 static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, 296 BinaryOperator::Opcode op, const llvm::APSInt& rhs, 297 QualType t) { 298 ID.AddInteger((unsigned) SymIntKind); 299 ID.AddPointer(lhs); 300 ID.AddInteger(op); 301 ID.AddPointer(&rhs); 302 ID.Add(t); 303 } 304 Profile(llvm::FoldingSetNodeID & ID)305 void Profile(llvm::FoldingSetNodeID& ID) { 306 Profile(ID, LHS, Op, RHS, T); 307 } 308 309 // Implement isa<T> support. classof(const SymExpr * SE)310 static inline bool classof(const SymExpr* SE) { 311 return SE->getKind() == SymIntKind; 312 } 313 }; 314 315 // SymSymExpr - Represents symbolic expression like 'x' + 'y'. 316 class SymSymExpr : public SymExpr { 317 const SymExpr *LHS; 318 BinaryOperator::Opcode Op; 319 const SymExpr *RHS; 320 QualType T; 321 322 public: SymSymExpr(const SymExpr * lhs,BinaryOperator::Opcode op,const SymExpr * rhs,QualType t)323 SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, 324 QualType t) 325 : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} 326 getOpcode()327 BinaryOperator::Opcode getOpcode() const { return Op; } getLHS()328 const SymExpr *getLHS() const { return LHS; } getRHS()329 const SymExpr *getRHS() const { return RHS; } 330 331 // FIXME: We probably need to make this out-of-line to avoid redundant 332 // generation of virtual functions. getType(ASTContext & C)333 QualType getType(ASTContext& C) const { return T; } 334 335 void dumpToStream(llvm::raw_ostream &os) const; 336 Profile(llvm::FoldingSetNodeID & ID,const SymExpr * lhs,BinaryOperator::Opcode op,const SymExpr * rhs,QualType t)337 static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, 338 BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) { 339 ID.AddInteger((unsigned) SymSymKind); 340 ID.AddPointer(lhs); 341 ID.AddInteger(op); 342 ID.AddPointer(rhs); 343 ID.Add(t); 344 } 345 Profile(llvm::FoldingSetNodeID & ID)346 void Profile(llvm::FoldingSetNodeID& ID) { 347 Profile(ID, LHS, Op, RHS, T); 348 } 349 350 // Implement isa<T> support. classof(const SymExpr * SE)351 static inline bool classof(const SymExpr* SE) { 352 return SE->getKind() == SymSymKind; 353 } 354 }; 355 356 class SymbolManager { 357 typedef llvm::FoldingSet<SymExpr> DataSetTy; 358 DataSetTy DataSet; 359 unsigned SymbolCounter; 360 llvm::BumpPtrAllocator& BPAlloc; 361 BasicValueFactory &BV; 362 ASTContext& Ctx; 363 364 public: SymbolManager(ASTContext & ctx,BasicValueFactory & bv,llvm::BumpPtrAllocator & bpalloc)365 SymbolManager(ASTContext& ctx, BasicValueFactory &bv, 366 llvm::BumpPtrAllocator& bpalloc) 367 : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {} 368 369 ~SymbolManager(); 370 371 static bool canSymbolicate(QualType T); 372 373 /// Make a unique symbol for MemRegion R according to its kind. 374 const SymbolRegionValue* getRegionValueSymbol(const TypedRegion* R); 375 376 const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T, 377 unsigned VisitCount, 378 const void* SymbolTag = 0); 379 380 const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount, 381 const void* SymbolTag = 0) { 382 return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag); 383 } 384 385 const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol, 386 const TypedRegion *R); 387 388 const SymbolExtent *getExtentSymbol(const SubRegion *R); 389 390 const SymbolMetadata* getMetadataSymbol(const MemRegion* R, const Stmt* S, 391 QualType T, unsigned VisitCount, 392 const void* SymbolTag = 0); 393 394 const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, 395 const llvm::APSInt& rhs, QualType t); 396 getSymIntExpr(const SymExpr & lhs,BinaryOperator::Opcode op,const llvm::APSInt & rhs,QualType t)397 const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op, 398 const llvm::APSInt& rhs, QualType t) { 399 return getSymIntExpr(&lhs, op, rhs, t); 400 } 401 402 const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, 403 const SymExpr *rhs, QualType t); 404 getType(const SymExpr * SE)405 QualType getType(const SymExpr *SE) const { 406 return SE->getType(Ctx); 407 } 408 getContext()409 ASTContext &getContext() { return Ctx; } getBasicVals()410 BasicValueFactory &getBasicVals() { return BV; } 411 }; 412 413 class SymbolReaper { 414 typedef llvm::DenseSet<SymbolRef> SetTy; 415 416 SetTy TheLiving; 417 SetTy MetadataInUse; 418 SetTy TheDead; 419 const LocationContext *LCtx; 420 const Stmt *Loc; 421 SymbolManager& SymMgr; 422 423 public: SymbolReaper(const LocationContext * ctx,const Stmt * s,SymbolManager & symmgr)424 SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr) 425 : LCtx(ctx), Loc(s), SymMgr(symmgr) {} 426 ~SymbolReaper()427 ~SymbolReaper() {} 428 getLocationContext()429 const LocationContext *getLocationContext() const { return LCtx; } getCurrentStatement()430 const Stmt *getCurrentStatement() const { return Loc; } 431 432 bool isLive(SymbolRef sym); 433 bool isLive(const Stmt *ExprVal) const; 434 bool isLive(const VarRegion *VR) const; 435 436 // markLive - Unconditionally marks a symbol as live. This should never be 437 // used by checkers, only by the state infrastructure such as the store and 438 // environment. Checkers should instead use metadata symbols and markInUse. 439 void markLive(SymbolRef sym); 440 441 // markInUse - Marks a symbol as important to a checker. For metadata symbols, 442 // this will keep the symbol alive as long as its associated region is also 443 // live. For other symbols, this has no effect; checkers are not permitted 444 // to influence the life of other symbols. This should be used before any 445 // symbol marking has occurred, i.e. in the MarkLiveSymbols callback. 446 void markInUse(SymbolRef sym); 447 448 // maybeDead - If a symbol is known to be live, marks the symbol as live. 449 // Otherwise, if the symbol cannot be proven live, it is marked as dead. 450 // Returns true if the symbol is dead, false if live. 451 bool maybeDead(SymbolRef sym); 452 453 typedef SetTy::const_iterator dead_iterator; dead_begin()454 dead_iterator dead_begin() const { return TheDead.begin(); } dead_end()455 dead_iterator dead_end() const { return TheDead.end(); } 456 hasDeadSymbols()457 bool hasDeadSymbols() const { 458 return !TheDead.empty(); 459 } 460 461 /// isDead - Returns whether or not a symbol has been confirmed dead. This 462 /// should only be called once all marking of dead symbols has completed. 463 /// (For checkers, this means only in the evalDeadSymbols callback.) isDead(SymbolRef sym)464 bool isDead(SymbolRef sym) const { 465 return TheDead.count(sym); 466 } 467 }; 468 469 class SymbolVisitor { 470 public: 471 // VisitSymbol - A visitor method invoked by 472 // GRStateManager::scanReachableSymbols. The method returns \c true if 473 // symbols should continue be scanned and \c false otherwise. 474 virtual bool VisitSymbol(SymbolRef sym) = 0; 475 virtual ~SymbolVisitor(); 476 }; 477 478 } // end GR namespace 479 480 } // end clang namespace 481 482 namespace llvm { 483 static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, 484 const clang::ento::SymExpr *SE) { 485 SE->dumpToStream(os); 486 return os; 487 } 488 } // end llvm namespace 489 #endif 490