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 << ") ("; 69 Operand->dumpToStream(os); 70 os << ')'; 71 } 72 73 void UnarySymExpr::dumpToStream(raw_ostream &os) const { 74 os << UnaryOperator::getOpcodeStr(Op); 75 bool Binary = isa<BinarySymExpr>(Operand); 76 if (Binary) 77 os << '('; 78 Operand->dumpToStream(os); 79 if (Binary) 80 os << ')'; 81 } 82 83 void SymbolConjured::dumpToStream(raw_ostream &os) const { 84 os << getKindStr() << getSymbolID() << '{' << T << ", LC" << LCtx->getID(); 85 if (S) 86 os << ", S" << S->getID(LCtx->getDecl()->getASTContext()); 87 else 88 os << ", no stmt"; 89 os << ", #" << Count << '}'; 90 } 91 92 void SymbolDerived::dumpToStream(raw_ostream &os) const { 93 os << getKindStr() << getSymbolID() << '{' << getParentSymbol() << ',' 94 << getRegion() << '}'; 95 } 96 97 void SymbolExtent::dumpToStream(raw_ostream &os) const { 98 os << getKindStr() << getSymbolID() << '{' << getRegion() << '}'; 99 } 100 101 void SymbolMetadata::dumpToStream(raw_ostream &os) const { 102 os << getKindStr() << getSymbolID() << '{' << getRegion() << ',' << T << '}'; 103 } 104 105 void SymbolData::anchor() {} 106 107 void SymbolRegionValue::dumpToStream(raw_ostream &os) const { 108 os << getKindStr() << getSymbolID() << '<' << getType() << ' ' << R << '>'; 109 } 110 111 bool SymExpr::symbol_iterator::operator==(const symbol_iterator &X) const { 112 return itr == X.itr; 113 } 114 115 bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const { 116 return itr != X.itr; 117 } 118 119 SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) { 120 itr.push_back(SE); 121 } 122 123 SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() { 124 assert(!itr.empty() && "attempting to iterate on an 'end' iterator"); 125 expand(); 126 return *this; 127 } 128 129 SymbolRef SymExpr::symbol_iterator::operator*() { 130 assert(!itr.empty() && "attempting to dereference an 'end' iterator"); 131 return itr.back(); 132 } 133 134 void SymExpr::symbol_iterator::expand() { 135 const SymExpr *SE = itr.pop_back_val(); 136 137 switch (SE->getKind()) { 138 case SymExpr::SymbolRegionValueKind: 139 case SymExpr::SymbolConjuredKind: 140 case SymExpr::SymbolDerivedKind: 141 case SymExpr::SymbolExtentKind: 142 case SymExpr::SymbolMetadataKind: 143 return; 144 case SymExpr::SymbolCastKind: 145 itr.push_back(cast<SymbolCast>(SE)->getOperand()); 146 return; 147 case SymExpr::UnarySymExprKind: 148 itr.push_back(cast<UnarySymExpr>(SE)->getOperand()); 149 return; 150 case SymExpr::SymIntExprKind: 151 itr.push_back(cast<SymIntExpr>(SE)->getLHS()); 152 return; 153 case SymExpr::IntSymExprKind: 154 itr.push_back(cast<IntSymExpr>(SE)->getRHS()); 155 return; 156 case SymExpr::SymSymExprKind: { 157 const auto *x = cast<SymSymExpr>(SE); 158 itr.push_back(x->getLHS()); 159 itr.push_back(x->getRHS()); 160 return; 161 } 162 } 163 llvm_unreachable("unhandled expansion case"); 164 } 165 166 QualType SymbolConjured::getType() const { 167 return T; 168 } 169 170 QualType SymbolDerived::getType() const { 171 return R->getValueType(); 172 } 173 174 QualType SymbolExtent::getType() const { 175 ASTContext &Ctx = R->getMemRegionManager().getContext(); 176 return Ctx.getSizeType(); 177 } 178 179 QualType SymbolMetadata::getType() const { 180 return T; 181 } 182 183 QualType SymbolRegionValue::getType() const { 184 return R->getValueType(); 185 } 186 187 bool SymbolManager::canSymbolicate(QualType T) { 188 T = T.getCanonicalType(); 189 190 if (Loc::isLocType(T)) 191 return true; 192 193 if (T->isIntegralOrEnumerationType()) 194 return true; 195 196 if (T->isRecordType() && !T->isUnionType()) 197 return true; 198 199 return false; 200 } 201 202 void SymbolManager::addSymbolDependency(const SymbolRef Primary, 203 const SymbolRef Dependent) { 204 auto &dependencies = SymbolDependencies[Primary]; 205 if (!dependencies) { 206 dependencies = std::make_unique<SymbolRefSmallVectorTy>(); 207 } 208 dependencies->push_back(Dependent); 209 } 210 211 const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols( 212 const SymbolRef Primary) { 213 SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary); 214 if (I == SymbolDependencies.end()) 215 return nullptr; 216 return I->second.get(); 217 } 218 219 void SymbolReaper::markDependentsLive(SymbolRef sym) { 220 // Do not mark dependents more then once. 221 SymbolMapTy::iterator LI = TheLiving.find(sym); 222 assert(LI != TheLiving.end() && "The primary symbol is not live."); 223 if (LI->second == HaveMarkedDependents) 224 return; 225 LI->second = HaveMarkedDependents; 226 227 if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) { 228 for (const auto I : *Deps) { 229 if (TheLiving.contains(I)) 230 continue; 231 markLive(I); 232 } 233 } 234 } 235 236 void SymbolReaper::markLive(SymbolRef sym) { 237 TheLiving[sym] = NotProcessed; 238 markDependentsLive(sym); 239 } 240 241 void SymbolReaper::markLive(const MemRegion *region) { 242 LiveRegionRoots.insert(region->getBaseRegion()); 243 markElementIndicesLive(region); 244 } 245 246 void SymbolReaper::markLazilyCopied(const clang::ento::MemRegion *region) { 247 LazilyCopiedRegionRoots.insert(region->getBaseRegion()); 248 } 249 250 void SymbolReaper::markElementIndicesLive(const MemRegion *region) { 251 for (auto SR = dyn_cast<SubRegion>(region); SR; 252 SR = dyn_cast<SubRegion>(SR->getSuperRegion())) { 253 if (const auto ER = dyn_cast<ElementRegion>(SR)) { 254 SVal Idx = ER->getIndex(); 255 for (SymbolRef Sym : Idx.symbols()) 256 markLive(Sym); 257 } 258 } 259 } 260 261 void SymbolReaper::markInUse(SymbolRef sym) { 262 if (isa<SymbolMetadata>(sym)) 263 MetadataInUse.insert(sym); 264 } 265 266 bool SymbolReaper::isLiveRegion(const MemRegion *MR) { 267 // TODO: For now, liveness of a memory region is equivalent to liveness of its 268 // base region. In fact we can do a bit better: say, if a particular FieldDecl 269 // is not used later in the path, we can diagnose a leak of a value within 270 // that field earlier than, say, the variable that contains the field dies. 271 MR = MR->getBaseRegion(); 272 if (LiveRegionRoots.count(MR)) 273 return true; 274 275 if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) 276 return isLive(SR->getSymbol()); 277 278 if (const auto *VR = dyn_cast<VarRegion>(MR)) 279 return isLive(VR, true); 280 281 // FIXME: This is a gross over-approximation. What we really need is a way to 282 // tell if anything still refers to this region. Unlike SymbolicRegions, 283 // AllocaRegions don't have associated symbols, though, so we don't actually 284 // have a way to track their liveness. 285 return isa<AllocaRegion, CXXThisRegion, MemSpaceRegion, CodeTextRegion>(MR); 286 } 287 288 bool SymbolReaper::isLazilyCopiedRegion(const MemRegion *MR) const { 289 // TODO: See comment in isLiveRegion. 290 return LazilyCopiedRegionRoots.count(MR->getBaseRegion()); 291 } 292 293 bool SymbolReaper::isReadableRegion(const MemRegion *MR) { 294 return isLiveRegion(MR) || isLazilyCopiedRegion(MR); 295 } 296 297 bool SymbolReaper::isLive(SymbolRef sym) { 298 if (TheLiving.count(sym)) { 299 markDependentsLive(sym); 300 return true; 301 } 302 303 bool KnownLive; 304 305 switch (sym->getKind()) { 306 case SymExpr::SymbolRegionValueKind: 307 KnownLive = isReadableRegion(cast<SymbolRegionValue>(sym)->getRegion()); 308 break; 309 case SymExpr::SymbolConjuredKind: 310 KnownLive = false; 311 break; 312 case SymExpr::SymbolDerivedKind: 313 KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol()); 314 break; 315 case SymExpr::SymbolExtentKind: 316 KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion()); 317 break; 318 case SymExpr::SymbolMetadataKind: 319 KnownLive = MetadataInUse.count(sym) && 320 isLiveRegion(cast<SymbolMetadata>(sym)->getRegion()); 321 if (KnownLive) 322 MetadataInUse.erase(sym); 323 break; 324 case SymExpr::SymIntExprKind: 325 KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS()); 326 break; 327 case SymExpr::IntSymExprKind: 328 KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS()); 329 break; 330 case SymExpr::SymSymExprKind: 331 KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) && 332 isLive(cast<SymSymExpr>(sym)->getRHS()); 333 break; 334 case SymExpr::SymbolCastKind: 335 KnownLive = isLive(cast<SymbolCast>(sym)->getOperand()); 336 break; 337 case SymExpr::UnarySymExprKind: 338 KnownLive = isLive(cast<UnarySymExpr>(sym)->getOperand()); 339 break; 340 } 341 342 if (KnownLive) 343 markLive(sym); 344 345 return KnownLive; 346 } 347 348 bool 349 SymbolReaper::isLive(const Expr *ExprVal, const LocationContext *ELCtx) const { 350 if (LCtx == nullptr) 351 return false; 352 353 if (LCtx != ELCtx) { 354 // If the reaper's location context is a parent of the expression's 355 // location context, then the expression value is now "out of scope". 356 if (LCtx->isParentOf(ELCtx)) 357 return false; 358 return true; 359 } 360 361 // If no statement is provided, everything in this and parent contexts is 362 // live. 363 if (!Loc) 364 return true; 365 366 return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal); 367 } 368 369 bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{ 370 const StackFrameContext *VarContext = VR->getStackFrame(); 371 372 if (!VarContext) 373 return true; 374 375 if (!LCtx) 376 return false; 377 const StackFrameContext *CurrentContext = LCtx->getStackFrame(); 378 379 if (VarContext == CurrentContext) { 380 // If no statement is provided, everything is live. 381 if (!Loc) 382 return true; 383 384 // Anonymous parameters of an inheriting constructor are live for the entire 385 // duration of the constructor. 386 if (isa<CXXInheritedCtorInitExpr>(Loc)) 387 return true; 388 389 if (LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, VR->getDecl())) 390 return true; 391 392 if (!includeStoreBindings) 393 return false; 394 395 unsigned &cachedQuery = 396 const_cast<SymbolReaper *>(this)->includedRegionCache[VR]; 397 398 if (cachedQuery) { 399 return cachedQuery == 1; 400 } 401 402 // Query the store to see if the region occurs in any live bindings. 403 if (Store store = reapedStore.getStore()) { 404 bool hasRegion = 405 reapedStore.getStoreManager().includedInBindings(store, VR); 406 cachedQuery = hasRegion ? 1 : 2; 407 return hasRegion; 408 } 409 410 return false; 411 } 412 413 return VarContext->isParentOf(CurrentContext); 414 } 415