clang API Documentation

SymbolManager.cpp
Go to the documentation of this file.
00001 //== SymbolManager.h - Management of Symbolic Values ------------*- C++ -*--==//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines SymbolManager, a class that manages symbolic values
00011 //  created for use by ExprEngine and related classes.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
00016 #include "clang/Analysis/Analyses/LiveVariables.h"
00017 #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
00018 #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
00019 #include "llvm/Support/raw_ostream.h"
00020 
00021 using namespace clang;
00022 using namespace ento;
00023 
00024 void SymExpr::anchor() { }
00025 
00026 void SymExpr::dump() const {
00027   dumpToStream(llvm::errs());
00028 }
00029 
00030 void SymIntExpr::dumpToStream(raw_ostream &os) const {
00031   os << '(';
00032   getLHS()->dumpToStream(os);
00033   os << ") "
00034      << BinaryOperator::getOpcodeStr(getOpcode()) << ' '
00035      << getRHS().getZExtValue();
00036   if (getRHS().isUnsigned())
00037     os << 'U';
00038 }
00039 
00040 void IntSymExpr::dumpToStream(raw_ostream &os) const {
00041   os << getLHS().getZExtValue();
00042   if (getLHS().isUnsigned())
00043     os << 'U';
00044   os << ' '
00045      << BinaryOperator::getOpcodeStr(getOpcode())
00046      << " (";
00047   getRHS()->dumpToStream(os);
00048   os << ')';
00049 }
00050 
00051 void SymSymExpr::dumpToStream(raw_ostream &os) const {
00052   os << '(';
00053   getLHS()->dumpToStream(os);
00054   os << ") "
00055      << BinaryOperator::getOpcodeStr(getOpcode())
00056      << " (";
00057   getRHS()->dumpToStream(os);
00058   os << ')';
00059 }
00060 
00061 void SymbolCast::dumpToStream(raw_ostream &os) const {
00062   os << '(' << ToTy.getAsString() << ") (";
00063   Operand->dumpToStream(os);
00064   os << ')';
00065 }
00066 
00067 void SymbolConjured::dumpToStream(raw_ostream &os) const {
00068   os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}';
00069 }
00070 
00071 void SymbolDerived::dumpToStream(raw_ostream &os) const {
00072   os << "derived_$" << getSymbolID() << '{'
00073      << getParentSymbol() << ',' << getRegion() << '}';
00074 }
00075 
00076 void SymbolExtent::dumpToStream(raw_ostream &os) const {
00077   os << "extent_$" << getSymbolID() << '{' << getRegion() << '}';
00078 }
00079 
00080 void SymbolMetadata::dumpToStream(raw_ostream &os) const {
00081   os << "meta_$" << getSymbolID() << '{'
00082      << getRegion() << ',' << T.getAsString() << '}';
00083 }
00084 
00085 void SymbolData::anchor() { }
00086 
00087 void SymbolRegionValue::dumpToStream(raw_ostream &os) const {
00088   os << "reg_$" << getSymbolID() << "<" << R << ">";
00089 }
00090 
00091 bool SymExpr::symbol_iterator::operator==(const symbol_iterator &X) const {
00092   return itr == X.itr;
00093 }
00094 
00095 bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const {
00096   return itr != X.itr;
00097 }
00098 
00099 SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) {
00100   itr.push_back(SE);
00101 }
00102 
00103 SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() {
00104   assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
00105   expand();
00106   return *this;
00107 }
00108 
00109 SymbolRef SymExpr::symbol_iterator::operator*() {
00110   assert(!itr.empty() && "attempting to dereference an 'end' iterator");
00111   return itr.back();
00112 }
00113 
00114 void SymExpr::symbol_iterator::expand() {
00115   const SymExpr *SE = itr.pop_back_val();
00116 
00117   switch (SE->getKind()) {
00118     case SymExpr::RegionValueKind:
00119     case SymExpr::ConjuredKind:
00120     case SymExpr::DerivedKind:
00121     case SymExpr::ExtentKind:
00122     case SymExpr::MetadataKind:
00123       return;
00124     case SymExpr::CastSymbolKind:
00125       itr.push_back(cast<SymbolCast>(SE)->getOperand());
00126       return;
00127     case SymExpr::SymIntKind:
00128       itr.push_back(cast<SymIntExpr>(SE)->getLHS());
00129       return;
00130     case SymExpr::IntSymKind:
00131       itr.push_back(cast<IntSymExpr>(SE)->getRHS());
00132       return;
00133     case SymExpr::SymSymKind: {
00134       const SymSymExpr *x = cast<SymSymExpr>(SE);
00135       itr.push_back(x->getLHS());
00136       itr.push_back(x->getRHS());
00137       return;
00138     }
00139   }
00140   llvm_unreachable("unhandled expansion case");
00141 }
00142 
00143 unsigned SymExpr::computeComplexity() const {
00144   unsigned R = 0;
00145   for (symbol_iterator I = symbol_begin(), E = symbol_end(); I != E; ++I)
00146     R++;
00147   return R;
00148 }
00149 
00150 const SymbolRegionValue*
00151 SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
00152   llvm::FoldingSetNodeID profile;
00153   SymbolRegionValue::Profile(profile, R);
00154   void *InsertPos;
00155   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
00156   if (!SD) {
00157     SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
00158     new (SD) SymbolRegionValue(SymbolCounter, R);
00159     DataSet.InsertNode(SD, InsertPos);
00160     ++SymbolCounter;
00161   }
00162 
00163   return cast<SymbolRegionValue>(SD);
00164 }
00165 
00166 const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E,
00167                                                    const LocationContext *LCtx,
00168                                                    QualType T,
00169                                                    unsigned Count,
00170                                                    const void *SymbolTag) {
00171   llvm::FoldingSetNodeID profile;
00172   SymbolConjured::Profile(profile, E, T, Count, LCtx, SymbolTag);
00173   void *InsertPos;
00174   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
00175   if (!SD) {
00176     SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
00177     new (SD) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag);
00178     DataSet.InsertNode(SD, InsertPos);
00179     ++SymbolCounter;
00180   }
00181 
00182   return cast<SymbolConjured>(SD);
00183 }
00184 
00185 const SymbolDerived*
00186 SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
00187                                 const TypedValueRegion *R) {
00188 
00189   llvm::FoldingSetNodeID profile;
00190   SymbolDerived::Profile(profile, parentSymbol, R);
00191   void *InsertPos;
00192   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
00193   if (!SD) {
00194     SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>();
00195     new (SD) SymbolDerived(SymbolCounter, parentSymbol, R);
00196     DataSet.InsertNode(SD, InsertPos);
00197     ++SymbolCounter;
00198   }
00199 
00200   return cast<SymbolDerived>(SD);
00201 }
00202 
00203 const SymbolExtent*
00204 SymbolManager::getExtentSymbol(const SubRegion *R) {
00205   llvm::FoldingSetNodeID profile;
00206   SymbolExtent::Profile(profile, R);
00207   void *InsertPos;
00208   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
00209   if (!SD) {
00210     SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>();
00211     new (SD) SymbolExtent(SymbolCounter, R);
00212     DataSet.InsertNode(SD, InsertPos);
00213     ++SymbolCounter;
00214   }
00215 
00216   return cast<SymbolExtent>(SD);
00217 }
00218 
00219 const SymbolMetadata*
00220 SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T,
00221                                  unsigned Count, const void *SymbolTag) {
00222 
00223   llvm::FoldingSetNodeID profile;
00224   SymbolMetadata::Profile(profile, R, S, T, Count, SymbolTag);
00225   void *InsertPos;
00226   SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
00227   if (!SD) {
00228     SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>();
00229     new (SD) SymbolMetadata(SymbolCounter, R, S, T, Count, SymbolTag);
00230     DataSet.InsertNode(SD, InsertPos);
00231     ++SymbolCounter;
00232   }
00233 
00234   return cast<SymbolMetadata>(SD);
00235 }
00236 
00237 const SymbolCast*
00238 SymbolManager::getCastSymbol(const SymExpr *Op,
00239                              QualType From, QualType To) {
00240   llvm::FoldingSetNodeID ID;
00241   SymbolCast::Profile(ID, Op, From, To);
00242   void *InsertPos;
00243   SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
00244   if (!data) {
00245     data = (SymbolCast*) BPAlloc.Allocate<SymbolCast>();
00246     new (data) SymbolCast(Op, From, To);
00247     DataSet.InsertNode(data, InsertPos);
00248   }
00249 
00250   return cast<SymbolCast>(data);
00251 }
00252 
00253 const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
00254                                                BinaryOperator::Opcode op,
00255                                                const llvm::APSInt& v,
00256                                                QualType t) {
00257   llvm::FoldingSetNodeID ID;
00258   SymIntExpr::Profile(ID, lhs, op, v, t);
00259   void *InsertPos;
00260   SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
00261 
00262   if (!data) {
00263     data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>();
00264     new (data) SymIntExpr(lhs, op, v, t);
00265     DataSet.InsertNode(data, InsertPos);
00266   }
00267 
00268   return cast<SymIntExpr>(data);
00269 }
00270 
00271 const IntSymExpr *SymbolManager::getIntSymExpr(const llvm::APSInt& lhs,
00272                                                BinaryOperator::Opcode op,
00273                                                const SymExpr *rhs,
00274                                                QualType t) {
00275   llvm::FoldingSetNodeID ID;
00276   IntSymExpr::Profile(ID, lhs, op, rhs, t);
00277   void *InsertPos;
00278   SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
00279 
00280   if (!data) {
00281     data = (IntSymExpr*) BPAlloc.Allocate<IntSymExpr>();
00282     new (data) IntSymExpr(lhs, op, rhs, t);
00283     DataSet.InsertNode(data, InsertPos);
00284   }
00285 
00286   return cast<IntSymExpr>(data);
00287 }
00288 
00289 const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
00290                                                BinaryOperator::Opcode op,
00291                                                const SymExpr *rhs,
00292                                                QualType t) {
00293   llvm::FoldingSetNodeID ID;
00294   SymSymExpr::Profile(ID, lhs, op, rhs, t);
00295   void *InsertPos;
00296   SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
00297 
00298   if (!data) {
00299     data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>();
00300     new (data) SymSymExpr(lhs, op, rhs, t);
00301     DataSet.InsertNode(data, InsertPos);
00302   }
00303 
00304   return cast<SymSymExpr>(data);
00305 }
00306 
00307 QualType SymbolConjured::getType() const {
00308   return T;
00309 }
00310 
00311 QualType SymbolDerived::getType() const {
00312   return R->getValueType();
00313 }
00314 
00315 QualType SymbolExtent::getType() const {
00316   ASTContext &Ctx = R->getMemRegionManager()->getContext();
00317   return Ctx.getSizeType();
00318 }
00319 
00320 QualType SymbolMetadata::getType() const {
00321   return T;
00322 }
00323 
00324 QualType SymbolRegionValue::getType() const {
00325   return R->getValueType();
00326 }
00327 
00328 SymbolManager::~SymbolManager() {
00329   llvm::DeleteContainerSeconds(SymbolDependencies);
00330 }
00331 
00332 bool SymbolManager::canSymbolicate(QualType T) {
00333   T = T.getCanonicalType();
00334 
00335   if (Loc::isLocType(T))
00336     return true;
00337 
00338   if (T->isIntegralOrEnumerationType())
00339     return true;
00340 
00341   if (T->isRecordType() && !T->isUnionType())
00342     return true;
00343 
00344   return false;
00345 }
00346 
00347 void SymbolManager::addSymbolDependency(const SymbolRef Primary,
00348                                         const SymbolRef Dependent) {
00349   SymbolDependTy::iterator I = SymbolDependencies.find(Primary);
00350   SymbolRefSmallVectorTy *dependencies = nullptr;
00351   if (I == SymbolDependencies.end()) {
00352     dependencies = new SymbolRefSmallVectorTy();
00353     SymbolDependencies[Primary] = dependencies;
00354   } else {
00355     dependencies = I->second;
00356   }
00357   dependencies->push_back(Dependent);
00358 }
00359 
00360 const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols(
00361                                                      const SymbolRef Primary) {
00362   SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary);
00363   if (I == SymbolDependencies.end())
00364     return nullptr;
00365   return I->second;
00366 }
00367 
00368 void SymbolReaper::markDependentsLive(SymbolRef sym) {
00369   // Do not mark dependents more then once.
00370   SymbolMapTy::iterator LI = TheLiving.find(sym);
00371   assert(LI != TheLiving.end() && "The primary symbol is not live.");
00372   if (LI->second == HaveMarkedDependents)
00373     return;
00374   LI->second = HaveMarkedDependents;
00375 
00376   if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) {
00377     for (SymbolRefSmallVectorTy::const_iterator I = Deps->begin(),
00378                                                 E = Deps->end(); I != E; ++I) {
00379       if (TheLiving.find(*I) != TheLiving.end())
00380         continue;
00381       markLive(*I);
00382     }
00383   }
00384 }
00385 
00386 void SymbolReaper::markLive(SymbolRef sym) {
00387   TheLiving[sym] = NotProcessed;
00388   TheDead.erase(sym);
00389   markDependentsLive(sym);
00390 }
00391 
00392 void SymbolReaper::markLive(const MemRegion *region) {
00393   RegionRoots.insert(region);
00394 }
00395 
00396 void SymbolReaper::markInUse(SymbolRef sym) {
00397   if (isa<SymbolMetadata>(sym))
00398     MetadataInUse.insert(sym);
00399 }
00400 
00401 bool SymbolReaper::maybeDead(SymbolRef sym) {
00402   if (isLive(sym))
00403     return false;
00404 
00405   TheDead.insert(sym);
00406   return true;
00407 }
00408 
00409 bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
00410   if (RegionRoots.count(MR))
00411     return true;
00412   
00413   MR = MR->getBaseRegion();
00414 
00415   if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
00416     return isLive(SR->getSymbol());
00417 
00418   if (const VarRegion *VR = dyn_cast<VarRegion>(MR))
00419     return isLive(VR, true);
00420 
00421   // FIXME: This is a gross over-approximation. What we really need is a way to
00422   // tell if anything still refers to this region. Unlike SymbolicRegions,
00423   // AllocaRegions don't have associated symbols, though, so we don't actually
00424   // have a way to track their liveness.
00425   if (isa<AllocaRegion>(MR))
00426     return true;
00427 
00428   if (isa<CXXThisRegion>(MR))
00429     return true;
00430 
00431   if (isa<MemSpaceRegion>(MR))
00432     return true;
00433 
00434   if (isa<CodeTextRegion>(MR))
00435     return true;
00436 
00437   return false;
00438 }
00439 
00440 bool SymbolReaper::isLive(SymbolRef sym) {
00441   if (TheLiving.count(sym)) {
00442     markDependentsLive(sym);
00443     return true;
00444   }
00445   
00446   bool KnownLive;
00447   
00448   switch (sym->getKind()) {
00449   case SymExpr::RegionValueKind:
00450     KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion());
00451     break;
00452   case SymExpr::ConjuredKind:
00453     KnownLive = false;
00454     break;
00455   case SymExpr::DerivedKind:
00456     KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol());
00457     break;
00458   case SymExpr::ExtentKind:
00459     KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion());
00460     break;
00461   case SymExpr::MetadataKind:
00462     KnownLive = MetadataInUse.count(sym) &&
00463                 isLiveRegion(cast<SymbolMetadata>(sym)->getRegion());
00464     if (KnownLive)
00465       MetadataInUse.erase(sym);
00466     break;
00467   case SymExpr::SymIntKind:
00468     KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS());
00469     break;
00470   case SymExpr::IntSymKind:
00471     KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS());
00472     break;
00473   case SymExpr::SymSymKind:
00474     KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) &&
00475                 isLive(cast<SymSymExpr>(sym)->getRHS());
00476     break;
00477   case SymExpr::CastSymbolKind:
00478     KnownLive = isLive(cast<SymbolCast>(sym)->getOperand());
00479     break;
00480   }
00481 
00482   if (KnownLive)
00483     markLive(sym);
00484 
00485   return KnownLive;
00486 }
00487 
00488 bool
00489 SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const {
00490   if (LCtx == nullptr)
00491     return false;
00492 
00493   if (LCtx != ELCtx) {
00494     // If the reaper's location context is a parent of the expression's
00495     // location context, then the expression value is now "out of scope".
00496     if (LCtx->isParentOf(ELCtx))
00497       return false;
00498     return true;
00499   }
00500 
00501   // If no statement is provided, everything is this and parent contexts is live.
00502   if (!Loc)
00503     return true;
00504 
00505   return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal);
00506 }
00507 
00508 bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
00509   const StackFrameContext *VarContext = VR->getStackFrame();
00510 
00511   if (!VarContext)
00512     return true;
00513 
00514   if (!LCtx)
00515     return false;
00516   const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame();
00517 
00518   if (VarContext == CurrentContext) {
00519     // If no statement is provided, everything is live.
00520     if (!Loc)
00521       return true;
00522 
00523     if (LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, VR->getDecl()))
00524       return true;
00525 
00526     if (!includeStoreBindings)
00527       return false;
00528     
00529     unsigned &cachedQuery =
00530       const_cast<SymbolReaper*>(this)->includedRegionCache[VR];
00531 
00532     if (cachedQuery) {
00533       return cachedQuery == 1;
00534     }
00535 
00536     // Query the store to see if the region occurs in any live bindings.
00537     if (Store store = reapedStore.getStore()) {
00538       bool hasRegion = 
00539         reapedStore.getStoreManager().includedInBindings(store, VR);
00540       cachedQuery = hasRegion ? 1 : 2;
00541       return hasRegion;
00542     }
00543     
00544     return false;
00545   }
00546 
00547   return VarContext->isParentOf(CurrentContext);
00548 }
00549 
00550 SymbolVisitor::~SymbolVisitor() {}