1 //===- SymbolManager.h - Management of Symbolic Values ----------*- 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 SymbolManager, a class that manages symbolic values 10 // created for use by ExprEngine and related classes. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H 15 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H 16 17 #include "clang/AST/Expr.h" 18 #include "clang/AST/Type.h" 19 #include "clang/Analysis/AnalysisDeclContext.h" 20 #include "clang/Basic/LLVM.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntPtr.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" 24 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" 25 #include "llvm/ADT/DenseMap.h" 26 #include "llvm/ADT/DenseSet.h" 27 #include "llvm/ADT/FoldingSet.h" 28 #include "llvm/ADT/ImmutableSet.h" 29 #include "llvm/ADT/iterator_range.h" 30 #include "llvm/Support/Allocator.h" 31 #include <cassert> 32 33 namespace clang { 34 35 class ASTContext; 36 class Stmt; 37 38 namespace ento { 39 40 class BasicValueFactory; 41 class StoreManager; 42 43 ///A symbol representing the value stored at a MemRegion. 44 class SymbolRegionValue : public SymbolData { 45 const TypedValueRegion *R; 46 47 friend class SymExprAllocator; 48 SymbolRegionValue(SymbolID sym, const TypedValueRegion *r) 49 : SymbolData(SymbolRegionValueKind, sym), R(r) { 50 assert(r); 51 assert(isValidTypeForSymbol(r->getValueType())); 52 } 53 54 public: 55 LLVM_ATTRIBUTE_RETURNS_NONNULL 56 const TypedValueRegion *getRegion() const { return R; } 57 58 static void Profile(llvm::FoldingSetNodeID& profile, const TypedValueRegion* R) { 59 profile.AddInteger((unsigned) SymbolRegionValueKind); 60 profile.AddPointer(R); 61 } 62 63 void Profile(llvm::FoldingSetNodeID& profile) override { 64 Profile(profile, R); 65 } 66 67 StringRef getKindStr() const override; 68 69 void dumpToStream(raw_ostream &os) const override; 70 const MemRegion *getOriginRegion() const override { return getRegion(); } 71 72 QualType getType() const override; 73 74 // Implement isa<T> support. 75 static bool classof(const SymExpr *SE) { 76 return SE->getKind() == SymbolRegionValueKind; 77 } 78 }; 79 80 /// A symbol representing the result of an expression in the case when we do 81 /// not know anything about what the expression is. 82 class SymbolConjured : public SymbolData { 83 const Stmt *S; 84 QualType T; 85 unsigned Count; 86 const LocationContext *LCtx; 87 const void *SymbolTag; 88 89 friend class SymExprAllocator; 90 SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx, 91 QualType t, unsigned count, const void *symbolTag) 92 : SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count), 93 LCtx(lctx), SymbolTag(symbolTag) { 94 // FIXME: 's' might be a nullptr if we're conducting invalidation 95 // that was caused by a destructor call on a temporary object, 96 // which has no statement associated with it. 97 // Due to this, we might be creating the same invalidation symbol for 98 // two different invalidation passes (for two different temporaries). 99 assert(lctx); 100 assert(isValidTypeForSymbol(t)); 101 } 102 103 public: 104 /// It might return null. 105 const Stmt *getStmt() const { return S; } 106 unsigned getCount() const { return Count; } 107 /// It might return null. 108 const void *getTag() const { return SymbolTag; } 109 110 QualType getType() const override; 111 112 StringRef getKindStr() const override; 113 114 void dumpToStream(raw_ostream &os) const override; 115 116 static void Profile(llvm::FoldingSetNodeID &profile, const Stmt *S, 117 const LocationContext *LCtx, QualType T, unsigned Count, 118 const void *SymbolTag) { 119 profile.AddInteger((unsigned)SymbolConjuredKind); 120 profile.AddPointer(S); 121 profile.AddPointer(LCtx); 122 profile.Add(T); 123 profile.AddInteger(Count); 124 profile.AddPointer(SymbolTag); 125 } 126 127 void Profile(llvm::FoldingSetNodeID& profile) override { 128 Profile(profile, S, LCtx, T, Count, SymbolTag); 129 } 130 131 // Implement isa<T> support. 132 static bool classof(const SymExpr *SE) { 133 return SE->getKind() == SymbolConjuredKind; 134 } 135 }; 136 137 /// A symbol representing the value of a MemRegion whose parent region has 138 /// symbolic value. 139 class SymbolDerived : public SymbolData { 140 SymbolRef parentSymbol; 141 const TypedValueRegion *R; 142 143 friend class SymExprAllocator; 144 SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r) 145 : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) { 146 assert(parent); 147 assert(r); 148 assert(isValidTypeForSymbol(r->getValueType())); 149 } 150 151 public: 152 LLVM_ATTRIBUTE_RETURNS_NONNULL 153 SymbolRef getParentSymbol() const { return parentSymbol; } 154 LLVM_ATTRIBUTE_RETURNS_NONNULL 155 const TypedValueRegion *getRegion() const { return R; } 156 157 QualType getType() const override; 158 159 StringRef getKindStr() const override; 160 161 void dumpToStream(raw_ostream &os) const override; 162 const MemRegion *getOriginRegion() const override { return getRegion(); } 163 164 static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent, 165 const TypedValueRegion *r) { 166 profile.AddInteger((unsigned) SymbolDerivedKind); 167 profile.AddPointer(r); 168 profile.AddPointer(parent); 169 } 170 171 void Profile(llvm::FoldingSetNodeID& profile) override { 172 Profile(profile, parentSymbol, R); 173 } 174 175 // Implement isa<T> support. 176 static bool classof(const SymExpr *SE) { 177 return SE->getKind() == SymbolDerivedKind; 178 } 179 }; 180 181 /// SymbolExtent - Represents the extent (size in bytes) of a bounded region. 182 /// Clients should not ask the SymbolManager for a region's extent. Always use 183 /// SubRegion::getExtent instead -- the value returned may not be a symbol. 184 class SymbolExtent : public SymbolData { 185 const SubRegion *R; 186 187 friend class SymExprAllocator; 188 SymbolExtent(SymbolID sym, const SubRegion *r) 189 : SymbolData(SymbolExtentKind, sym), R(r) { 190 assert(r); 191 } 192 193 public: 194 LLVM_ATTRIBUTE_RETURNS_NONNULL 195 const SubRegion *getRegion() const { return R; } 196 197 QualType getType() const override; 198 199 StringRef getKindStr() const override; 200 201 void dumpToStream(raw_ostream &os) const override; 202 203 static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) { 204 profile.AddInteger((unsigned) SymbolExtentKind); 205 profile.AddPointer(R); 206 } 207 208 void Profile(llvm::FoldingSetNodeID& profile) override { 209 Profile(profile, R); 210 } 211 212 // Implement isa<T> support. 213 static bool classof(const SymExpr *SE) { 214 return SE->getKind() == SymbolExtentKind; 215 } 216 }; 217 218 /// SymbolMetadata - Represents path-dependent metadata about a specific region. 219 /// Metadata symbols remain live as long as they are marked as in use before 220 /// dead-symbol sweeping AND their associated regions are still alive. 221 /// Intended for use by checkers. 222 class SymbolMetadata : public SymbolData { 223 const MemRegion* R; 224 const Stmt *S; 225 QualType T; 226 const LocationContext *LCtx; 227 /// Count can be used to differentiate regions corresponding to 228 /// different loop iterations, thus, making the symbol path-dependent. 229 unsigned Count; 230 const void *Tag; 231 232 friend class SymExprAllocator; 233 SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t, 234 const LocationContext *LCtx, unsigned count, const void *tag) 235 : SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), LCtx(LCtx), 236 Count(count), Tag(tag) { 237 assert(r); 238 assert(s); 239 assert(isValidTypeForSymbol(t)); 240 assert(LCtx); 241 assert(tag); 242 } 243 244 public: 245 LLVM_ATTRIBUTE_RETURNS_NONNULL 246 const MemRegion *getRegion() const { return R; } 247 248 LLVM_ATTRIBUTE_RETURNS_NONNULL 249 const Stmt *getStmt() const { return S; } 250 251 LLVM_ATTRIBUTE_RETURNS_NONNULL 252 const LocationContext *getLocationContext() const { return LCtx; } 253 254 unsigned getCount() const { return Count; } 255 256 LLVM_ATTRIBUTE_RETURNS_NONNULL 257 const void *getTag() const { return Tag; } 258 259 QualType getType() const override; 260 261 StringRef getKindStr() const override; 262 263 void dumpToStream(raw_ostream &os) const override; 264 265 static void Profile(llvm::FoldingSetNodeID &profile, const MemRegion *R, 266 const Stmt *S, QualType T, const LocationContext *LCtx, 267 unsigned Count, const void *Tag) { 268 profile.AddInteger((unsigned)SymbolMetadataKind); 269 profile.AddPointer(R); 270 profile.AddPointer(S); 271 profile.Add(T); 272 profile.AddPointer(LCtx); 273 profile.AddInteger(Count); 274 profile.AddPointer(Tag); 275 } 276 277 void Profile(llvm::FoldingSetNodeID& profile) override { 278 Profile(profile, R, S, T, LCtx, Count, Tag); 279 } 280 281 // Implement isa<T> support. 282 static bool classof(const SymExpr *SE) { 283 return SE->getKind() == SymbolMetadataKind; 284 } 285 }; 286 287 /// Represents a cast expression. 288 class SymbolCast : public SymExpr { 289 const SymExpr *Operand; 290 291 /// Type of the operand. 292 QualType FromTy; 293 294 /// The type of the result. 295 QualType ToTy; 296 297 friend class SymExprAllocator; 298 SymbolCast(SymbolID Sym, const SymExpr *In, QualType From, QualType To) 299 : SymExpr(SymbolCastKind, Sym), Operand(In), FromTy(From), ToTy(To) { 300 assert(In); 301 assert(isValidTypeForSymbol(From)); 302 // FIXME: GenericTaintChecker creates symbols of void type. 303 // Otherwise, 'To' should also be a valid type. 304 } 305 306 public: 307 unsigned computeComplexity() const override { 308 if (Complexity == 0) 309 Complexity = 1 + Operand->computeComplexity(); 310 return Complexity; 311 } 312 313 QualType getType() const override { return ToTy; } 314 315 LLVM_ATTRIBUTE_RETURNS_NONNULL 316 const SymExpr *getOperand() const { return Operand; } 317 318 void dumpToStream(raw_ostream &os) const override; 319 320 static void Profile(llvm::FoldingSetNodeID& ID, 321 const SymExpr *In, QualType From, QualType To) { 322 ID.AddInteger((unsigned) SymbolCastKind); 323 ID.AddPointer(In); 324 ID.Add(From); 325 ID.Add(To); 326 } 327 328 void Profile(llvm::FoldingSetNodeID& ID) override { 329 Profile(ID, Operand, FromTy, ToTy); 330 } 331 332 // Implement isa<T> support. 333 static bool classof(const SymExpr *SE) { 334 return SE->getKind() == SymbolCastKind; 335 } 336 }; 337 338 /// Represents a symbolic expression involving a unary operator. 339 class UnarySymExpr : public SymExpr { 340 const SymExpr *Operand; 341 UnaryOperator::Opcode Op; 342 QualType T; 343 344 friend class SymExprAllocator; 345 UnarySymExpr(SymbolID Sym, const SymExpr *In, UnaryOperator::Opcode Op, 346 QualType T) 347 : SymExpr(UnarySymExprKind, Sym), Operand(In), Op(Op), T(T) { 348 // Note, some unary operators are modeled as a binary operator. E.g. ++x is 349 // modeled as x + 1. 350 assert((Op == UO_Minus || Op == UO_Not) && "non-supported unary expression"); 351 // Unary expressions are results of arithmetic. Pointer arithmetic is not 352 // handled by unary expressions, but it is instead handled by applying 353 // sub-regions to regions. 354 assert(isValidTypeForSymbol(T) && "non-valid type for unary symbol"); 355 assert(!Loc::isLocType(T) && "unary symbol should be nonloc"); 356 } 357 358 public: 359 unsigned computeComplexity() const override { 360 if (Complexity == 0) 361 Complexity = 1 + Operand->computeComplexity(); 362 return Complexity; 363 } 364 365 const SymExpr *getOperand() const { return Operand; } 366 UnaryOperator::Opcode getOpcode() const { return Op; } 367 QualType getType() const override { return T; } 368 369 void dumpToStream(raw_ostream &os) const override; 370 371 static void Profile(llvm::FoldingSetNodeID &ID, const SymExpr *In, 372 UnaryOperator::Opcode Op, QualType T) { 373 ID.AddInteger((unsigned)UnarySymExprKind); 374 ID.AddPointer(In); 375 ID.AddInteger(Op); 376 ID.Add(T); 377 } 378 379 void Profile(llvm::FoldingSetNodeID &ID) override { 380 Profile(ID, Operand, Op, T); 381 } 382 383 // Implement isa<T> support. 384 static bool classof(const SymExpr *SE) { 385 return SE->getKind() == UnarySymExprKind; 386 } 387 }; 388 389 /// Represents a symbolic expression involving a binary operator 390 class BinarySymExpr : public SymExpr { 391 BinaryOperator::Opcode Op; 392 QualType T; 393 394 protected: 395 BinarySymExpr(SymbolID Sym, Kind k, BinaryOperator::Opcode op, QualType t) 396 : SymExpr(k, Sym), Op(op), T(t) { 397 assert(classof(this)); 398 // Binary expressions are results of arithmetic. Pointer arithmetic is not 399 // handled by binary expressions, but it is instead handled by applying 400 // sub-regions to regions. 401 assert(isValidTypeForSymbol(t) && !Loc::isLocType(t)); 402 } 403 404 public: 405 // FIXME: We probably need to make this out-of-line to avoid redundant 406 // generation of virtual functions. 407 QualType getType() const override { return T; } 408 409 BinaryOperator::Opcode getOpcode() const { return Op; } 410 411 // Implement isa<T> support. 412 static bool classof(const SymExpr *SE) { 413 Kind k = SE->getKind(); 414 return k >= BEGIN_BINARYSYMEXPRS && k <= END_BINARYSYMEXPRS; 415 } 416 417 protected: 418 static unsigned computeOperandComplexity(const SymExpr *Value) { 419 return Value->computeComplexity(); 420 } 421 static unsigned computeOperandComplexity(const llvm::APSInt &Value) { 422 return 1; 423 } 424 425 static const llvm::APSInt *getPointer(APSIntPtr Value) { return Value.get(); } 426 static const SymExpr *getPointer(const SymExpr *Value) { return Value; } 427 428 static void dumpToStreamImpl(raw_ostream &os, const SymExpr *Value); 429 static void dumpToStreamImpl(raw_ostream &os, const llvm::APSInt &Value); 430 static void dumpToStreamImpl(raw_ostream &os, BinaryOperator::Opcode op); 431 }; 432 433 /// Template implementation for all binary symbolic expressions 434 template <class LHSTYPE, class RHSTYPE, SymExpr::Kind ClassKind> 435 class BinarySymExprImpl : public BinarySymExpr { 436 LHSTYPE LHS; 437 RHSTYPE RHS; 438 439 friend class SymExprAllocator; 440 BinarySymExprImpl(SymbolID Sym, LHSTYPE lhs, BinaryOperator::Opcode op, 441 RHSTYPE rhs, QualType t) 442 : BinarySymExpr(Sym, ClassKind, op, t), LHS(lhs), RHS(rhs) { 443 assert(getPointer(lhs)); 444 assert(getPointer(rhs)); 445 } 446 447 public: 448 void dumpToStream(raw_ostream &os) const override { 449 dumpToStreamImpl(os, LHS); 450 dumpToStreamImpl(os, getOpcode()); 451 dumpToStreamImpl(os, RHS); 452 } 453 454 LHSTYPE getLHS() const { return LHS; } 455 RHSTYPE getRHS() const { return RHS; } 456 457 unsigned computeComplexity() const override { 458 if (Complexity == 0) 459 Complexity = 460 computeOperandComplexity(RHS) + computeOperandComplexity(LHS); 461 return Complexity; 462 } 463 464 static void Profile(llvm::FoldingSetNodeID &ID, LHSTYPE lhs, 465 BinaryOperator::Opcode op, RHSTYPE rhs, QualType t) { 466 ID.AddInteger((unsigned)ClassKind); 467 ID.AddPointer(getPointer(lhs)); 468 ID.AddInteger(op); 469 ID.AddPointer(getPointer(rhs)); 470 ID.Add(t); 471 } 472 473 void Profile(llvm::FoldingSetNodeID &ID) override { 474 Profile(ID, LHS, getOpcode(), RHS, getType()); 475 } 476 477 // Implement isa<T> support. 478 static bool classof(const SymExpr *SE) { return SE->getKind() == ClassKind; } 479 }; 480 481 /// Represents a symbolic expression like 'x' + 3. 482 using SymIntExpr = BinarySymExprImpl<const SymExpr *, APSIntPtr, 483 SymExpr::Kind::SymIntExprKind>; 484 485 /// Represents a symbolic expression like 3 - 'x'. 486 using IntSymExpr = BinarySymExprImpl<APSIntPtr, const SymExpr *, 487 SymExpr::Kind::IntSymExprKind>; 488 489 /// Represents a symbolic expression like 'x' + 'y'. 490 using SymSymExpr = BinarySymExprImpl<const SymExpr *, const SymExpr *, 491 SymExpr::Kind::SymSymExprKind>; 492 493 class SymExprAllocator { 494 SymbolID NextSymbolID = 0; 495 llvm::BumpPtrAllocator &Alloc; 496 497 public: 498 explicit SymExprAllocator(llvm::BumpPtrAllocator &Alloc) : Alloc(Alloc) {} 499 500 template <class SymT, typename... ArgsT> SymT *make(ArgsT &&...Args) { 501 return new (Alloc) SymT(nextID(), std::forward<ArgsT>(Args)...); 502 } 503 504 private: 505 SymbolID nextID() { return NextSymbolID++; } 506 }; 507 508 class SymbolManager { 509 using DataSetTy = llvm::FoldingSet<SymExpr>; 510 using SymbolDependTy = 511 llvm::DenseMap<SymbolRef, std::unique_ptr<SymbolRefSmallVectorTy>>; 512 513 DataSetTy DataSet; 514 515 /// Stores the extra dependencies between symbols: the data should be kept 516 /// alive as long as the key is live. 517 SymbolDependTy SymbolDependencies; 518 519 SymExprAllocator Alloc; 520 BasicValueFactory &BV; 521 ASTContext &Ctx; 522 523 public: 524 SymbolManager(ASTContext &ctx, BasicValueFactory &bv, 525 llvm::BumpPtrAllocator &bpalloc) 526 : SymbolDependencies(16), Alloc(bpalloc), BV(bv), Ctx(ctx) {} 527 528 static bool canSymbolicate(QualType T); 529 530 /// Create or retrieve a SymExpr of type \p SymExprT for the given arguments. 531 /// Use the arguments to check for an existing SymExpr and return it, 532 /// otherwise, create a new one and keep a pointer to it to avoid duplicates. 533 template <typename SymExprT, typename... Args> 534 const SymExprT *acquire(Args &&...args); 535 536 const SymbolConjured *conjureSymbol(const Stmt *E, 537 const LocationContext *LCtx, QualType T, 538 unsigned VisitCount, 539 const void *SymbolTag = nullptr) { 540 return acquire<SymbolConjured>(E, LCtx, T, VisitCount, SymbolTag); 541 } 542 543 const SymbolConjured* conjureSymbol(const Expr *E, 544 const LocationContext *LCtx, 545 unsigned VisitCount, 546 const void *SymbolTag = nullptr) { 547 return conjureSymbol(E, LCtx, E->getType(), VisitCount, SymbolTag); 548 } 549 550 QualType getType(const SymExpr *SE) const { 551 return SE->getType(); 552 } 553 554 /// Add artificial symbol dependency. 555 /// 556 /// The dependent symbol should stay alive as long as the primary is alive. 557 void addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent); 558 559 const SymbolRefSmallVectorTy *getDependentSymbols(const SymbolRef Primary); 560 561 ASTContext &getContext() { return Ctx; } 562 BasicValueFactory &getBasicVals() { return BV; } 563 }; 564 565 /// A class responsible for cleaning up unused symbols. 566 class SymbolReaper { 567 enum SymbolStatus { 568 NotProcessed, 569 HaveMarkedDependents 570 }; 571 572 using SymbolSetTy = llvm::DenseSet<SymbolRef>; 573 using SymbolMapTy = llvm::DenseMap<SymbolRef, SymbolStatus>; 574 using RegionSetTy = llvm::DenseSet<const MemRegion *>; 575 576 SymbolMapTy TheLiving; 577 SymbolSetTy MetadataInUse; 578 579 RegionSetTy LiveRegionRoots; 580 // The lazily copied regions are locations for which a program 581 // can access the value stored at that location, but not its address. 582 // These regions are constructed as a set of regions referred to by 583 // lazyCompoundVal. 584 RegionSetTy LazilyCopiedRegionRoots; 585 586 const StackFrameContext *LCtx; 587 const Stmt *Loc; 588 SymbolManager& SymMgr; 589 StoreRef reapedStore; 590 llvm::DenseMap<const MemRegion *, unsigned> includedRegionCache; 591 592 public: 593 /// Construct a reaper object, which removes everything which is not 594 /// live before we execute statement s in the given location context. 595 /// 596 /// If the statement is NULL, everything is this and parent contexts is 597 /// considered live. 598 /// If the stack frame context is NULL, everything on stack is considered 599 /// dead. 600 SymbolReaper(const StackFrameContext *Ctx, const Stmt *s, 601 SymbolManager &symmgr, StoreManager &storeMgr) 602 : LCtx(Ctx), Loc(s), SymMgr(symmgr), reapedStore(nullptr, storeMgr) {} 603 604 /// It might return null. 605 const LocationContext *getLocationContext() const { return LCtx; } 606 607 bool isLive(SymbolRef sym); 608 bool isLiveRegion(const MemRegion *region); 609 bool isLive(const Expr *ExprVal, const LocationContext *LCtx) const; 610 bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const; 611 612 /// Unconditionally marks a symbol as live. 613 /// 614 /// This should never be 615 /// used by checkers, only by the state infrastructure such as the store and 616 /// environment. Checkers should instead use metadata symbols and markInUse. 617 void markLive(SymbolRef sym); 618 619 /// Marks a symbol as important to a checker. 620 /// 621 /// For metadata symbols, 622 /// this will keep the symbol alive as long as its associated region is also 623 /// live. For other symbols, this has no effect; checkers are not permitted 624 /// to influence the life of other symbols. This should be used before any 625 /// symbol marking has occurred, i.e. in the MarkLiveSymbols callback. 626 void markInUse(SymbolRef sym); 627 628 llvm::iterator_range<RegionSetTy::const_iterator> regions() const { 629 return LiveRegionRoots; 630 } 631 632 /// Returns whether or not a symbol has been confirmed dead. 633 /// 634 /// This should only be called once all marking of dead symbols has completed. 635 /// (For checkers, this means only in the checkDeadSymbols callback.) 636 bool isDead(SymbolRef sym) { 637 return !isLive(sym); 638 } 639 640 void markLive(const MemRegion *region); 641 void markLazilyCopied(const MemRegion *region); 642 void markElementIndicesLive(const MemRegion *region); 643 644 /// Set to the value of the symbolic store after 645 /// StoreManager::removeDeadBindings has been called. 646 void setReapedStore(StoreRef st) { reapedStore = st; } 647 648 private: 649 bool isLazilyCopiedRegion(const MemRegion *region) const; 650 // A readable region is a region that live or lazily copied. 651 // Any symbols that refer to values in regions are alive if the region 652 // is readable. 653 bool isReadableRegion(const MemRegion *region); 654 655 /// Mark the symbols dependent on the input symbol as live. 656 void markDependentsLive(SymbolRef sym); 657 }; 658 659 class SymbolVisitor { 660 protected: 661 ~SymbolVisitor() = default; 662 663 public: 664 SymbolVisitor() = default; 665 SymbolVisitor(const SymbolVisitor &) = default; 666 SymbolVisitor(SymbolVisitor &&) {} 667 668 // The copy and move assignment operator is defined as deleted pending further 669 // motivation. 670 SymbolVisitor &operator=(const SymbolVisitor &) = delete; 671 SymbolVisitor &operator=(SymbolVisitor &&) = delete; 672 673 /// A visitor method invoked by ProgramStateManager::scanReachableSymbols. 674 /// 675 /// The method returns \c true if symbols should continue be scanned and \c 676 /// false otherwise. 677 virtual bool VisitSymbol(SymbolRef sym) = 0; 678 virtual bool VisitMemRegion(const MemRegion *) { return true; } 679 }; 680 681 template <typename T, typename... Args> 682 const T *SymbolManager::acquire(Args &&...args) { 683 llvm::FoldingSetNodeID profile; 684 T::Profile(profile, args...); 685 void *InsertPos; 686 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 687 if (!SD) { 688 SD = Alloc.make<T>(std::forward<Args>(args)...); 689 DataSet.InsertNode(SD, InsertPos); 690 } 691 return cast<T>(SD); 692 } 693 694 } // namespace ento 695 696 } // namespace clang 697 698 // Override the default definition that would use pointer values of SymbolRefs 699 // to order them, which is unstable due to ASLR. 700 // Use the SymbolID instead which reflect the order in which the symbols were 701 // allocated. This is usually stable across runs leading to the stability of 702 // ConstraintMap and other containers using SymbolRef as keys. 703 template <> 704 struct llvm::ImutContainerInfo<clang::ento::SymbolRef> 705 : public ImutProfileInfo<clang::ento::SymbolRef> { 706 using value_type = clang::ento::SymbolRef; 707 using value_type_ref = clang::ento::SymbolRef; 708 using key_type = value_type; 709 using key_type_ref = value_type_ref; 710 using data_type = bool; 711 using data_type_ref = bool; 712 713 static key_type_ref KeyOfValue(value_type_ref D) { return D; } 714 static data_type_ref DataOfValue(value_type_ref) { return true; } 715 716 static bool isEqual(clang::ento::SymbolRef LHS, clang::ento::SymbolRef RHS) { 717 return LHS->getSymbolID() == RHS->getSymbolID(); 718 } 719 720 static bool isLess(clang::ento::SymbolRef LHS, clang::ento::SymbolRef RHS) { 721 return LHS->getSymbolID() < RHS->getSymbolID(); 722 } 723 724 // This might seem redundant, but it is required because of the way 725 // ImmutableSet is implemented through AVLTree: 726 // same as ImmutableMap, but with a non-informative "data". 727 static bool isDataEqual(data_type_ref, data_type_ref) { return true; } 728 }; 729 730 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H 731