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 "clang/StaticAnalyzer/Core/PathSensitive/Store.h" 19 #include "llvm/Support/raw_ostream.h" 20 21 using namespace clang; 22 using namespace ento; 23 24 void SymExpr::anchor() { } 25 26 LLVM_DUMP_METHOD void SymExpr::dump() const { 27 dumpToStream(llvm::errs()); 28 } 29 30 void SymIntExpr::dumpToStream(raw_ostream &os) const { 31 os << '('; 32 getLHS()->dumpToStream(os); 33 os << ") " 34 << BinaryOperator::getOpcodeStr(getOpcode()) << ' ' 35 << getRHS().getZExtValue(); 36 if (getRHS().isUnsigned()) 37 os << 'U'; 38 } 39 40 void IntSymExpr::dumpToStream(raw_ostream &os) const { 41 os << getLHS().getZExtValue(); 42 if (getLHS().isUnsigned()) 43 os << 'U'; 44 os << ' ' 45 << BinaryOperator::getOpcodeStr(getOpcode()) 46 << " ("; 47 getRHS()->dumpToStream(os); 48 os << ')'; 49 } 50 51 void SymSymExpr::dumpToStream(raw_ostream &os) const { 52 os << '('; 53 getLHS()->dumpToStream(os); 54 os << ") " 55 << BinaryOperator::getOpcodeStr(getOpcode()) 56 << " ("; 57 getRHS()->dumpToStream(os); 58 os << ')'; 59 } 60 61 void SymbolCast::dumpToStream(raw_ostream &os) const { 62 os << '(' << ToTy.getAsString() << ") ("; 63 Operand->dumpToStream(os); 64 os << ')'; 65 } 66 67 void SymbolConjured::dumpToStream(raw_ostream &os) const { 68 os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}'; 69 } 70 71 void SymbolDerived::dumpToStream(raw_ostream &os) const { 72 os << "derived_$" << getSymbolID() << '{' 73 << getParentSymbol() << ',' << getRegion() << '}'; 74 } 75 76 void SymbolExtent::dumpToStream(raw_ostream &os) const { 77 os << "extent_$" << getSymbolID() << '{' << getRegion() << '}'; 78 } 79 80 void SymbolMetadata::dumpToStream(raw_ostream &os) const { 81 os << "meta_$" << getSymbolID() << '{' 82 << getRegion() << ',' << T.getAsString() << '}'; 83 } 84 85 void SymbolData::anchor() { } 86 87 void SymbolRegionValue::dumpToStream(raw_ostream &os) const { 88 os << "reg_$" << getSymbolID() 89 << '<' << getType().getAsString() << ' ' << R << '>'; 90 } 91 92 bool SymExpr::symbol_iterator::operator==(const symbol_iterator &X) const { 93 return itr == X.itr; 94 } 95 96 bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const { 97 return itr != X.itr; 98 } 99 100 SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) { 101 itr.push_back(SE); 102 } 103 104 SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() { 105 assert(!itr.empty() && "attempting to iterate on an 'end' iterator"); 106 expand(); 107 return *this; 108 } 109 110 SymbolRef SymExpr::symbol_iterator::operator*() { 111 assert(!itr.empty() && "attempting to dereference an 'end' iterator"); 112 return itr.back(); 113 } 114 115 void SymExpr::symbol_iterator::expand() { 116 const SymExpr *SE = itr.pop_back_val(); 117 118 switch (SE->getKind()) { 119 case SymExpr::SymbolRegionValueKind: 120 case SymExpr::SymbolConjuredKind: 121 case SymExpr::SymbolDerivedKind: 122 case SymExpr::SymbolExtentKind: 123 case SymExpr::SymbolMetadataKind: 124 return; 125 case SymExpr::SymbolCastKind: 126 itr.push_back(cast<SymbolCast>(SE)->getOperand()); 127 return; 128 case SymExpr::SymIntExprKind: 129 itr.push_back(cast<SymIntExpr>(SE)->getLHS()); 130 return; 131 case SymExpr::IntSymExprKind: 132 itr.push_back(cast<IntSymExpr>(SE)->getRHS()); 133 return; 134 case SymExpr::SymSymExprKind: { 135 const SymSymExpr *x = cast<SymSymExpr>(SE); 136 itr.push_back(x->getLHS()); 137 itr.push_back(x->getRHS()); 138 return; 139 } 140 } 141 llvm_unreachable("unhandled expansion case"); 142 } 143 144 unsigned SymExpr::computeComplexity() const { 145 unsigned R = 0; 146 for (symbol_iterator I = symbol_begin(), E = symbol_end(); I != E; ++I) 147 R++; 148 return R; 149 } 150 151 const SymbolRegionValue* 152 SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) { 153 llvm::FoldingSetNodeID profile; 154 SymbolRegionValue::Profile(profile, R); 155 void *InsertPos; 156 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 157 if (!SD) { 158 SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>(); 159 new (SD) SymbolRegionValue(SymbolCounter, R); 160 DataSet.InsertNode(SD, InsertPos); 161 ++SymbolCounter; 162 } 163 164 return cast<SymbolRegionValue>(SD); 165 } 166 167 const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E, 168 const LocationContext *LCtx, 169 QualType T, 170 unsigned Count, 171 const void *SymbolTag) { 172 llvm::FoldingSetNodeID profile; 173 SymbolConjured::Profile(profile, E, T, Count, LCtx, SymbolTag); 174 void *InsertPos; 175 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 176 if (!SD) { 177 SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>(); 178 new (SD) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag); 179 DataSet.InsertNode(SD, InsertPos); 180 ++SymbolCounter; 181 } 182 183 return cast<SymbolConjured>(SD); 184 } 185 186 const SymbolDerived* 187 SymbolManager::getDerivedSymbol(SymbolRef parentSymbol, 188 const TypedValueRegion *R) { 189 190 llvm::FoldingSetNodeID profile; 191 SymbolDerived::Profile(profile, parentSymbol, R); 192 void *InsertPos; 193 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 194 if (!SD) { 195 SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>(); 196 new (SD) SymbolDerived(SymbolCounter, parentSymbol, R); 197 DataSet.InsertNode(SD, InsertPos); 198 ++SymbolCounter; 199 } 200 201 return cast<SymbolDerived>(SD); 202 } 203 204 const SymbolExtent* 205 SymbolManager::getExtentSymbol(const SubRegion *R) { 206 llvm::FoldingSetNodeID profile; 207 SymbolExtent::Profile(profile, R); 208 void *InsertPos; 209 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 210 if (!SD) { 211 SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>(); 212 new (SD) SymbolExtent(SymbolCounter, R); 213 DataSet.InsertNode(SD, InsertPos); 214 ++SymbolCounter; 215 } 216 217 return cast<SymbolExtent>(SD); 218 } 219 220 const SymbolMetadata * 221 SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T, 222 const LocationContext *LCtx, 223 unsigned Count, const void *SymbolTag) { 224 225 llvm::FoldingSetNodeID profile; 226 SymbolMetadata::Profile(profile, R, S, T, LCtx, Count, SymbolTag); 227 void *InsertPos; 228 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 229 if (!SD) { 230 SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>(); 231 new (SD) SymbolMetadata(SymbolCounter, R, S, T, LCtx, Count, SymbolTag); 232 DataSet.InsertNode(SD, InsertPos); 233 ++SymbolCounter; 234 } 235 236 return cast<SymbolMetadata>(SD); 237 } 238 239 const SymbolCast* 240 SymbolManager::getCastSymbol(const SymExpr *Op, 241 QualType From, QualType To) { 242 llvm::FoldingSetNodeID ID; 243 SymbolCast::Profile(ID, Op, From, To); 244 void *InsertPos; 245 SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); 246 if (!data) { 247 data = (SymbolCast*) BPAlloc.Allocate<SymbolCast>(); 248 new (data) SymbolCast(Op, From, To); 249 DataSet.InsertNode(data, InsertPos); 250 } 251 252 return cast<SymbolCast>(data); 253 } 254 255 const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs, 256 BinaryOperator::Opcode op, 257 const llvm::APSInt& v, 258 QualType t) { 259 llvm::FoldingSetNodeID ID; 260 SymIntExpr::Profile(ID, lhs, op, v, t); 261 void *InsertPos; 262 SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); 263 264 if (!data) { 265 data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>(); 266 new (data) SymIntExpr(lhs, op, v, t); 267 DataSet.InsertNode(data, InsertPos); 268 } 269 270 return cast<SymIntExpr>(data); 271 } 272 273 const IntSymExpr *SymbolManager::getIntSymExpr(const llvm::APSInt& lhs, 274 BinaryOperator::Opcode op, 275 const SymExpr *rhs, 276 QualType t) { 277 llvm::FoldingSetNodeID ID; 278 IntSymExpr::Profile(ID, lhs, op, rhs, t); 279 void *InsertPos; 280 SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); 281 282 if (!data) { 283 data = (IntSymExpr*) BPAlloc.Allocate<IntSymExpr>(); 284 new (data) IntSymExpr(lhs, op, rhs, t); 285 DataSet.InsertNode(data, InsertPos); 286 } 287 288 return cast<IntSymExpr>(data); 289 } 290 291 const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs, 292 BinaryOperator::Opcode op, 293 const SymExpr *rhs, 294 QualType t) { 295 llvm::FoldingSetNodeID ID; 296 SymSymExpr::Profile(ID, lhs, op, rhs, t); 297 void *InsertPos; 298 SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); 299 300 if (!data) { 301 data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>(); 302 new (data) SymSymExpr(lhs, op, rhs, t); 303 DataSet.InsertNode(data, InsertPos); 304 } 305 306 return cast<SymSymExpr>(data); 307 } 308 309 QualType SymbolConjured::getType() const { 310 return T; 311 } 312 313 QualType SymbolDerived::getType() const { 314 return R->getValueType(); 315 } 316 317 QualType SymbolExtent::getType() const { 318 ASTContext &Ctx = R->getMemRegionManager()->getContext(); 319 return Ctx.getSizeType(); 320 } 321 322 QualType SymbolMetadata::getType() const { 323 return T; 324 } 325 326 QualType SymbolRegionValue::getType() const { 327 return R->getValueType(); 328 } 329 330 SymbolManager::~SymbolManager() { 331 llvm::DeleteContainerSeconds(SymbolDependencies); 332 } 333 334 bool SymbolManager::canSymbolicate(QualType T) { 335 T = T.getCanonicalType(); 336 337 if (Loc::isLocType(T)) 338 return true; 339 340 if (T->isIntegralOrEnumerationType()) 341 return true; 342 343 if (T->isRecordType() && !T->isUnionType()) 344 return true; 345 346 return false; 347 } 348 349 void SymbolManager::addSymbolDependency(const SymbolRef Primary, 350 const SymbolRef Dependent) { 351 SymbolDependTy::iterator I = SymbolDependencies.find(Primary); 352 SymbolRefSmallVectorTy *dependencies = nullptr; 353 if (I == SymbolDependencies.end()) { 354 dependencies = new SymbolRefSmallVectorTy(); 355 SymbolDependencies[Primary] = dependencies; 356 } else { 357 dependencies = I->second; 358 } 359 dependencies->push_back(Dependent); 360 } 361 362 const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols( 363 const SymbolRef Primary) { 364 SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary); 365 if (I == SymbolDependencies.end()) 366 return nullptr; 367 return I->second; 368 } 369 370 void SymbolReaper::markDependentsLive(SymbolRef sym) { 371 // Do not mark dependents more then once. 372 SymbolMapTy::iterator LI = TheLiving.find(sym); 373 assert(LI != TheLiving.end() && "The primary symbol is not live."); 374 if (LI->second == HaveMarkedDependents) 375 return; 376 LI->second = HaveMarkedDependents; 377 378 if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) { 379 for (SymbolRefSmallVectorTy::const_iterator I = Deps->begin(), 380 E = Deps->end(); I != E; ++I) { 381 if (TheLiving.find(*I) != TheLiving.end()) 382 continue; 383 markLive(*I); 384 } 385 } 386 } 387 388 void SymbolReaper::markLive(SymbolRef sym) { 389 TheLiving[sym] = NotProcessed; 390 TheDead.erase(sym); 391 markDependentsLive(sym); 392 } 393 394 void SymbolReaper::markLive(const MemRegion *region) { 395 RegionRoots.insert(region); 396 markElementIndicesLive(region); 397 } 398 399 void SymbolReaper::markElementIndicesLive(const MemRegion *region) { 400 for (auto SR = dyn_cast<SubRegion>(region); SR; 401 SR = dyn_cast<SubRegion>(SR->getSuperRegion())) { 402 if (auto ER = dyn_cast<ElementRegion>(SR)) { 403 SVal Idx = ER->getIndex(); 404 for (auto SI = Idx.symbol_begin(), SE = Idx.symbol_end(); SI != SE; ++SI) 405 markLive(*SI); 406 } 407 } 408 } 409 410 void SymbolReaper::markInUse(SymbolRef sym) { 411 if (isa<SymbolMetadata>(sym)) 412 MetadataInUse.insert(sym); 413 } 414 415 bool SymbolReaper::maybeDead(SymbolRef sym) { 416 if (isLive(sym)) 417 return false; 418 419 TheDead.insert(sym); 420 return true; 421 } 422 423 bool SymbolReaper::isLiveRegion(const MemRegion *MR) { 424 if (RegionRoots.count(MR)) 425 return true; 426 427 MR = MR->getBaseRegion(); 428 429 if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) 430 return isLive(SR->getSymbol()); 431 432 if (const VarRegion *VR = dyn_cast<VarRegion>(MR)) 433 return isLive(VR, true); 434 435 // FIXME: This is a gross over-approximation. What we really need is a way to 436 // tell if anything still refers to this region. Unlike SymbolicRegions, 437 // AllocaRegions don't have associated symbols, though, so we don't actually 438 // have a way to track their liveness. 439 if (isa<AllocaRegion>(MR)) 440 return true; 441 442 if (isa<CXXThisRegion>(MR)) 443 return true; 444 445 if (isa<MemSpaceRegion>(MR)) 446 return true; 447 448 if (isa<CodeTextRegion>(MR)) 449 return true; 450 451 return false; 452 } 453 454 bool SymbolReaper::isLive(SymbolRef sym) { 455 if (TheLiving.count(sym)) { 456 markDependentsLive(sym); 457 return true; 458 } 459 460 bool KnownLive; 461 462 switch (sym->getKind()) { 463 case SymExpr::SymbolRegionValueKind: 464 KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion()); 465 break; 466 case SymExpr::SymbolConjuredKind: 467 KnownLive = false; 468 break; 469 case SymExpr::SymbolDerivedKind: 470 KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol()); 471 break; 472 case SymExpr::SymbolExtentKind: 473 KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion()); 474 break; 475 case SymExpr::SymbolMetadataKind: 476 KnownLive = MetadataInUse.count(sym) && 477 isLiveRegion(cast<SymbolMetadata>(sym)->getRegion()); 478 if (KnownLive) 479 MetadataInUse.erase(sym); 480 break; 481 case SymExpr::SymIntExprKind: 482 KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS()); 483 break; 484 case SymExpr::IntSymExprKind: 485 KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS()); 486 break; 487 case SymExpr::SymSymExprKind: 488 KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) && 489 isLive(cast<SymSymExpr>(sym)->getRHS()); 490 break; 491 case SymExpr::SymbolCastKind: 492 KnownLive = isLive(cast<SymbolCast>(sym)->getOperand()); 493 break; 494 } 495 496 if (KnownLive) 497 markLive(sym); 498 499 return KnownLive; 500 } 501 502 bool 503 SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const { 504 if (LCtx == nullptr) 505 return false; 506 507 if (LCtx != ELCtx) { 508 // If the reaper's location context is a parent of the expression's 509 // location context, then the expression value is now "out of scope". 510 if (LCtx->isParentOf(ELCtx)) 511 return false; 512 return true; 513 } 514 515 // If no statement is provided, everything is this and parent contexts is live. 516 if (!Loc) 517 return true; 518 519 return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal); 520 } 521 522 bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{ 523 const StackFrameContext *VarContext = VR->getStackFrame(); 524 525 if (!VarContext) 526 return true; 527 528 if (!LCtx) 529 return false; 530 const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame(); 531 532 if (VarContext == CurrentContext) { 533 // If no statement is provided, everything is live. 534 if (!Loc) 535 return true; 536 537 if (LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, VR->getDecl())) 538 return true; 539 540 if (!includeStoreBindings) 541 return false; 542 543 unsigned &cachedQuery = 544 const_cast<SymbolReaper*>(this)->includedRegionCache[VR]; 545 546 if (cachedQuery) { 547 return cachedQuery == 1; 548 } 549 550 // Query the store to see if the region occurs in any live bindings. 551 if (Store store = reapedStore.getStore()) { 552 bool hasRegion = 553 reapedStore.getStoreManager().includedInBindings(store, VR); 554 cachedQuery = hasRegion ? 1 : 2; 555 return hasRegion; 556 } 557 558 return false; 559 } 560 561 return VarContext->isParentOf(CurrentContext); 562 } 563