Home | History | Annotate | Download | only in Core
      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 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
     16 #include "clang/Analysis/Analyses/LiveVariables.h"
     17 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
     18 #include "llvm/Support/raw_ostream.h"
     19 
     20 using namespace clang;
     21 using namespace ento;
     22 
     23 void SymExpr::dump() const {
     24   dumpToStream(llvm::errs());
     25 }
     26 
     27 static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) {
     28   switch (Op) {
     29     default:
     30       assert(false && "operator printing not implemented");
     31       break;
     32     case BO_Mul: os << '*'  ; break;
     33     case BO_Div: os << '/'  ; break;
     34     case BO_Rem: os << '%'  ; break;
     35     case BO_Add: os << '+'  ; break;
     36     case BO_Sub: os << '-'  ; break;
     37     case BO_Shl: os << "<<" ; break;
     38     case BO_Shr: os << ">>" ; break;
     39     case BO_LT:  os << "<"  ; break;
     40     case BO_GT:  os << '>'  ; break;
     41     case BO_LE:  os << "<=" ; break;
     42     case BO_GE:  os << ">=" ; break;
     43     case BO_EQ:  os << "==" ; break;
     44     case BO_NE:  os << "!=" ; break;
     45     case BO_And: os << '&'  ; break;
     46     case BO_Xor: os << '^'  ; break;
     47     case BO_Or:  os << '|'  ; break;
     48   }
     49 }
     50 
     51 void SymIntExpr::dumpToStream(llvm::raw_ostream& os) const {
     52   os << '(';
     53   getLHS()->dumpToStream(os);
     54   os << ") ";
     55   print(os, getOpcode());
     56   os << ' ' << getRHS().getZExtValue();
     57   if (getRHS().isUnsigned()) os << 'U';
     58 }
     59 
     60 void SymSymExpr::dumpToStream(llvm::raw_ostream& os) const {
     61   os << '(';
     62   getLHS()->dumpToStream(os);
     63   os << ") ";
     64   os << '(';
     65   getRHS()->dumpToStream(os);
     66   os << ')';
     67 }
     68 
     69 void SymbolConjured::dumpToStream(llvm::raw_ostream& os) const {
     70   os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}';
     71 }
     72 
     73 void SymbolDerived::dumpToStream(llvm::raw_ostream& os) const {
     74   os << "derived_$" << getSymbolID() << '{'
     75      << getParentSymbol() << ',' << getRegion() << '}';
     76 }
     77 
     78 void SymbolExtent::dumpToStream(llvm::raw_ostream& os) const {
     79   os << "extent_$" << getSymbolID() << '{' << getRegion() << '}';
     80 }
     81 
     82 void SymbolMetadata::dumpToStream(llvm::raw_ostream& os) const {
     83   os << "meta_$" << getSymbolID() << '{'
     84      << getRegion() << ',' << T.getAsString() << '}';
     85 }
     86 
     87 void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const {
     88   os << "reg_$" << getSymbolID() << "<" << R << ">";
     89 }
     90 
     91 const SymbolRegionValue*
     92 SymbolManager::getRegionValueSymbol(const TypedRegion* R) {
     93   llvm::FoldingSetNodeID profile;
     94   SymbolRegionValue::Profile(profile, R);
     95   void* InsertPos;
     96   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
     97   if (!SD) {
     98     SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
     99     new (SD) SymbolRegionValue(SymbolCounter, R);
    100     DataSet.InsertNode(SD, InsertPos);
    101     ++SymbolCounter;
    102   }
    103 
    104   return cast<SymbolRegionValue>(SD);
    105 }
    106 
    107 const SymbolConjured*
    108 SymbolManager::getConjuredSymbol(const Stmt* E, QualType T, unsigned Count,
    109                                  const void* SymbolTag) {
    110 
    111   llvm::FoldingSetNodeID profile;
    112   SymbolConjured::Profile(profile, E, T, Count, SymbolTag);
    113   void* InsertPos;
    114   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
    115   if (!SD) {
    116     SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
    117     new (SD) SymbolConjured(SymbolCounter, E, T, Count, SymbolTag);
    118     DataSet.InsertNode(SD, InsertPos);
    119     ++SymbolCounter;
    120   }
    121 
    122   return cast<SymbolConjured>(SD);
    123 }
    124 
    125 const SymbolDerived*
    126 SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
    127                                 const TypedRegion *R) {
    128 
    129   llvm::FoldingSetNodeID profile;
    130   SymbolDerived::Profile(profile, parentSymbol, R);
    131   void* InsertPos;
    132   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
    133   if (!SD) {
    134     SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>();
    135     new (SD) SymbolDerived(SymbolCounter, parentSymbol, R);
    136     DataSet.InsertNode(SD, InsertPos);
    137     ++SymbolCounter;
    138   }
    139 
    140   return cast<SymbolDerived>(SD);
    141 }
    142 
    143 const SymbolExtent*
    144 SymbolManager::getExtentSymbol(const SubRegion *R) {
    145   llvm::FoldingSetNodeID profile;
    146   SymbolExtent::Profile(profile, R);
    147   void* InsertPos;
    148   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
    149   if (!SD) {
    150     SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>();
    151     new (SD) SymbolExtent(SymbolCounter, R);
    152     DataSet.InsertNode(SD, InsertPos);
    153     ++SymbolCounter;
    154   }
    155 
    156   return cast<SymbolExtent>(SD);
    157 }
    158 
    159 const SymbolMetadata*
    160 SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt* S, QualType T,
    161                                  unsigned Count, const void* SymbolTag) {
    162 
    163   llvm::FoldingSetNodeID profile;
    164   SymbolMetadata::Profile(profile, R, S, T, Count, SymbolTag);
    165   void* InsertPos;
    166   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
    167   if (!SD) {
    168     SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>();
    169     new (SD) SymbolMetadata(SymbolCounter, R, S, T, Count, SymbolTag);
    170     DataSet.InsertNode(SD, InsertPos);
    171     ++SymbolCounter;
    172   }
    173 
    174   return cast<SymbolMetadata>(SD);
    175 }
    176 
    177 const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
    178                                                BinaryOperator::Opcode op,
    179                                                const llvm::APSInt& v,
    180                                                QualType t) {
    181   llvm::FoldingSetNodeID ID;
    182   SymIntExpr::Profile(ID, lhs, op, v, t);
    183   void *InsertPos;
    184   SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
    185 
    186   if (!data) {
    187     data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>();
    188     new (data) SymIntExpr(lhs, op, v, t);
    189     DataSet.InsertNode(data, InsertPos);
    190   }
    191 
    192   return cast<SymIntExpr>(data);
    193 }
    194 
    195 const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
    196                                                BinaryOperator::Opcode op,
    197                                                const SymExpr *rhs,
    198                                                QualType t) {
    199   llvm::FoldingSetNodeID ID;
    200   SymSymExpr::Profile(ID, lhs, op, rhs, t);
    201   void *InsertPos;
    202   SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
    203 
    204   if (!data) {
    205     data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>();
    206     new (data) SymSymExpr(lhs, op, rhs, t);
    207     DataSet.InsertNode(data, InsertPos);
    208   }
    209 
    210   return cast<SymSymExpr>(data);
    211 }
    212 
    213 QualType SymbolConjured::getType(ASTContext&) const {
    214   return T;
    215 }
    216 
    217 QualType SymbolDerived::getType(ASTContext& Ctx) const {
    218   return R->getValueType();
    219 }
    220 
    221 QualType SymbolExtent::getType(ASTContext& Ctx) const {
    222   return Ctx.getSizeType();
    223 }
    224 
    225 QualType SymbolMetadata::getType(ASTContext&) const {
    226   return T;
    227 }
    228 
    229 QualType SymbolRegionValue::getType(ASTContext& C) const {
    230   return R->getValueType();
    231 }
    232 
    233 SymbolManager::~SymbolManager() {}
    234 
    235 bool SymbolManager::canSymbolicate(QualType T) {
    236   T = T.getCanonicalType();
    237 
    238   if (Loc::isLocType(T))
    239     return true;
    240 
    241   if (T->isIntegerType())
    242     return T->isScalarType();
    243 
    244   if (T->isRecordType() && !T->isUnionType())
    245     return true;
    246 
    247   return false;
    248 }
    249 
    250 void SymbolReaper::markLive(SymbolRef sym) {
    251   TheLiving.insert(sym);
    252   TheDead.erase(sym);
    253 }
    254 
    255 void SymbolReaper::markInUse(SymbolRef sym) {
    256   if (isa<SymbolMetadata>(sym))
    257     MetadataInUse.insert(sym);
    258 }
    259 
    260 bool SymbolReaper::maybeDead(SymbolRef sym) {
    261   if (isLive(sym))
    262     return false;
    263 
    264   TheDead.insert(sym);
    265   return true;
    266 }
    267 
    268 static bool IsLiveRegion(SymbolReaper &Reaper, const MemRegion *MR) {
    269   MR = MR->getBaseRegion();
    270 
    271   if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
    272     return Reaper.isLive(SR->getSymbol());
    273 
    274   if (const VarRegion *VR = dyn_cast<VarRegion>(MR))
    275     return Reaper.isLive(VR);
    276 
    277   // FIXME: This is a gross over-approximation. What we really need is a way to
    278   // tell if anything still refers to this region. Unlike SymbolicRegions,
    279   // AllocaRegions don't have associated symbols, though, so we don't actually
    280   // have a way to track their liveness.
    281   if (isa<AllocaRegion>(MR))
    282     return true;
    283 
    284   if (isa<CXXThisRegion>(MR))
    285     return true;
    286 
    287   if (isa<MemSpaceRegion>(MR))
    288     return true;
    289 
    290   return false;
    291 }
    292 
    293 bool SymbolReaper::isLive(SymbolRef sym) {
    294   if (TheLiving.count(sym))
    295     return true;
    296 
    297   if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) {
    298     if (isLive(derived->getParentSymbol())) {
    299       markLive(sym);
    300       return true;
    301     }
    302     return false;
    303   }
    304 
    305   if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) {
    306     if (IsLiveRegion(*this, extent->getRegion())) {
    307       markLive(sym);
    308       return true;
    309     }
    310     return false;
    311   }
    312 
    313   if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) {
    314     if (MetadataInUse.count(sym)) {
    315       if (IsLiveRegion(*this, metadata->getRegion())) {
    316         markLive(sym);
    317         MetadataInUse.erase(sym);
    318         return true;
    319       }
    320     }
    321     return false;
    322   }
    323 
    324   // Interogate the symbol.  It may derive from an input value to
    325   // the analyzed function/method.
    326   return isa<SymbolRegionValue>(sym);
    327 }
    328 
    329 bool SymbolReaper::isLive(const Stmt* ExprVal) const {
    330   return LCtx->getAnalysisContext()->getRelaxedLiveVariables()->
    331       isLive(Loc, ExprVal);
    332 }
    333 
    334 bool SymbolReaper::isLive(const VarRegion *VR) const {
    335   const StackFrameContext *VarContext = VR->getStackFrame();
    336   const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame();
    337 
    338   if (VarContext == CurrentContext)
    339     return LCtx->getAnalysisContext()->getRelaxedLiveVariables()->
    340         isLive(Loc, VR->getDecl());
    341 
    342   return VarContext->isParentOf(CurrentContext);
    343 }
    344 
    345 SymbolVisitor::~SymbolVisitor() {}
    346