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