clang API Documentation
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() {}