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