Home | History | Annotate | Download | only in PathSensitive
      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:
     52   SymExpr(Kind k) : K(k) {}
     53 
     54 public:
     55   virtual ~SymExpr() {}
     56 
     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.
     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:
     77   SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
     78 
     79 public:
     80   virtual ~SymbolData() {}
     81 
     82   SymbolID getSymbolID() const { return Sym; }
     83 
     84   // Implement isa<T> support.
     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:
     98   SymbolRegionValue(SymbolID sym, const TypedRegion *r)
     99     : SymbolData(RegionValueKind, sym), R(r) {}
    100 
    101   const TypedRegion* getRegion() const { return R; }
    102 
    103   static void Profile(llvm::FoldingSetNodeID& profile, const TypedRegion* R) {
    104     profile.AddInteger((unsigned) RegionValueKind);
    105     profile.AddPointer(R);
    106   }
    107 
    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.
    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:
    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 
    135   const Stmt* getStmt() const { return S; }
    136   unsigned getCount() const { return Count; }
    137   const void* getTag() const { return SymbolTag; }
    138 
    139   QualType getType(ASTContext&) const;
    140 
    141   void dumpToStream(llvm::raw_ostream &os) const;
    142 
    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 
    152   virtual void Profile(llvm::FoldingSetNodeID& profile) {
    153     Profile(profile, S, T, Count, SymbolTag);
    154   }
    155 
    156   // Implement isa<T> support.
    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:
    169   SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r)
    170     : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {}
    171 
    172   SymbolRef getParentSymbol() const { return parentSymbol; }
    173   const TypedRegion *getRegion() const { return R; }
    174 
    175   QualType getType(ASTContext&) const;
    176 
    177   void dumpToStream(llvm::raw_ostream &os) const;
    178 
    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 
    186   virtual void Profile(llvm::FoldingSetNodeID& profile) {
    187     Profile(profile, parentSymbol, R);
    188   }
    189 
    190   // Implement isa<T> support.
    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:
    203   SymbolExtent(SymbolID sym, const SubRegion *r)
    204   : SymbolData(ExtentKind, sym), R(r) {}
    205 
    206   const SubRegion *getRegion() const { return R; }
    207 
    208   QualType getType(ASTContext&) const;
    209 
    210   void dumpToStream(llvm::raw_ostream &os) const;
    211 
    212   static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) {
    213     profile.AddInteger((unsigned) ExtentKind);
    214     profile.AddPointer(R);
    215   }
    216 
    217   virtual void Profile(llvm::FoldingSetNodeID& profile) {
    218     Profile(profile, R);
    219   }
    220 
    221   // Implement isa<T> support.
    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:
    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 
    242   const MemRegion *getRegion() const { return R; }
    243   const Stmt* getStmt() const { return S; }
    244   unsigned getCount() const { return Count; }
    245   const void* getTag() const { return Tag; }
    246 
    247   QualType getType(ASTContext&) const;
    248 
    249   void dumpToStream(llvm::raw_ostream &os) const;
    250 
    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 
    262   virtual void Profile(llvm::FoldingSetNodeID& profile) {
    263     Profile(profile, R, S, T, Count, Tag);
    264   }
    265 
    266   // Implement isa<T> support.
    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:
    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.
    286   QualType getType(ASTContext& C) const { return T; }
    287 
    288   BinaryOperator::Opcode getOpcode() const { return Op; }
    289 
    290   void dumpToStream(llvm::raw_ostream &os) const;
    291 
    292   const SymExpr *getLHS() const { return LHS; }
    293   const llvm::APSInt &getRHS() const { return RHS; }
    294 
    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 
    305   void Profile(llvm::FoldingSetNodeID& ID) {
    306     Profile(ID, LHS, Op, RHS, T);
    307   }
    308 
    309   // Implement isa<T> support.
    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:
    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 
    327   BinaryOperator::Opcode getOpcode() const { return Op; }
    328   const SymExpr *getLHS() const { return LHS; }
    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.
    333   QualType getType(ASTContext& C) const { return T; }
    334 
    335   void dumpToStream(llvm::raw_ostream &os) const;
    336 
    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 
    346   void Profile(llvm::FoldingSetNodeID& ID) {
    347     Profile(ID, LHS, Op, RHS, T);
    348   }
    349 
    350   // Implement isa<T> support.
    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:
    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 
    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 
    405   QualType getType(const SymExpr *SE) const {
    406     return SE->getType(Ctx);
    407   }
    408 
    409   ASTContext &getContext() { return Ctx; }
    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:
    424   SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr)
    425    : LCtx(ctx), Loc(s), SymMgr(symmgr) {}
    426 
    427   ~SymbolReaper() {}
    428 
    429   const LocationContext *getLocationContext() const { return LCtx; }
    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;
    454   dead_iterator dead_begin() const { return TheDead.begin(); }
    455   dead_iterator dead_end() const { return TheDead.end(); }
    456 
    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.)
    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