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