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