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