xref: /llvm-project/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h (revision dd331082e706d833ec3cc897176cd2d3a622ce76)
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