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