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