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::dump() const { 25 dumpToStream(llvm::errs()); 26 } 27 28 static void print(raw_ostream &os, BinaryOperator::Opcode Op) { 29 switch (Op) { 30 default: 31 assert(false && "operator printing not implemented"); 32 break; 33 case BO_Mul: os << '*' ; break; 34 case BO_Div: os << '/' ; break; 35 case BO_Rem: os << '%' ; break; 36 case BO_Add: os << '+' ; break; 37 case BO_Sub: os << '-' ; break; 38 case BO_Shl: os << "<<" ; break; 39 case BO_Shr: os << ">>" ; break; 40 case BO_LT: os << "<" ; break; 41 case BO_GT: os << '>' ; break; 42 case BO_LE: os << "<=" ; break; 43 case BO_GE: os << ">=" ; break; 44 case BO_EQ: os << "==" ; break; 45 case BO_NE: os << "!=" ; break; 46 case BO_And: os << '&' ; break; 47 case BO_Xor: os << '^' ; break; 48 case BO_Or: os << '|' ; break; 49 } 50 } 51 52 void SymIntExpr::dumpToStream(raw_ostream &os) const { 53 os << '('; 54 getLHS()->dumpToStream(os); 55 os << ") "; 56 print(os, getOpcode()); 57 os << ' ' << getRHS().getZExtValue(); 58 if (getRHS().isUnsigned()) os << 'U'; 59 } 60 61 void SymSymExpr::dumpToStream(raw_ostream &os) const { 62 os << '('; 63 getLHS()->dumpToStream(os); 64 os << ") "; 65 os << '('; 66 getRHS()->dumpToStream(os); 67 os << ')'; 68 } 69 70 void SymbolConjured::dumpToStream(raw_ostream &os) const { 71 os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}'; 72 } 73 74 void SymbolDerived::dumpToStream(raw_ostream &os) const { 75 os << "derived_$" << getSymbolID() << '{' 76 << getParentSymbol() << ',' << getRegion() << '}'; 77 } 78 79 void SymbolExtent::dumpToStream(raw_ostream &os) const { 80 os << "extent_$" << getSymbolID() << '{' << getRegion() << '}'; 81 } 82 83 void SymbolMetadata::dumpToStream(raw_ostream &os) const { 84 os << "meta_$" << getSymbolID() << '{' 85 << getRegion() << ',' << T.getAsString() << '}'; 86 } 87 88 void SymbolRegionValue::dumpToStream(raw_ostream &os) const { 89 os << "reg_$" << getSymbolID() << "<" << R << ">"; 90 } 91 92 const SymbolRegionValue* 93 SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) { 94 llvm::FoldingSetNodeID profile; 95 SymbolRegionValue::Profile(profile, R); 96 void *InsertPos; 97 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 98 if (!SD) { 99 SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>(); 100 new (SD) SymbolRegionValue(SymbolCounter, R); 101 DataSet.InsertNode(SD, InsertPos); 102 ++SymbolCounter; 103 } 104 105 return cast<SymbolRegionValue>(SD); 106 } 107 108 const SymbolConjured* 109 SymbolManager::getConjuredSymbol(const Stmt *E, QualType T, unsigned Count, 110 const void *SymbolTag) { 111 112 llvm::FoldingSetNodeID profile; 113 SymbolConjured::Profile(profile, E, T, Count, SymbolTag); 114 void *InsertPos; 115 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 116 if (!SD) { 117 SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>(); 118 new (SD) SymbolConjured(SymbolCounter, E, T, Count, SymbolTag); 119 DataSet.InsertNode(SD, InsertPos); 120 ++SymbolCounter; 121 } 122 123 return cast<SymbolConjured>(SD); 124 } 125 126 const SymbolDerived* 127 SymbolManager::getDerivedSymbol(SymbolRef parentSymbol, 128 const TypedValueRegion *R) { 129 130 llvm::FoldingSetNodeID profile; 131 SymbolDerived::Profile(profile, parentSymbol, R); 132 void *InsertPos; 133 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 134 if (!SD) { 135 SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>(); 136 new (SD) SymbolDerived(SymbolCounter, parentSymbol, R); 137 DataSet.InsertNode(SD, InsertPos); 138 ++SymbolCounter; 139 } 140 141 return cast<SymbolDerived>(SD); 142 } 143 144 const SymbolExtent* 145 SymbolManager::getExtentSymbol(const SubRegion *R) { 146 llvm::FoldingSetNodeID profile; 147 SymbolExtent::Profile(profile, R); 148 void *InsertPos; 149 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 150 if (!SD) { 151 SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>(); 152 new (SD) SymbolExtent(SymbolCounter, R); 153 DataSet.InsertNode(SD, InsertPos); 154 ++SymbolCounter; 155 } 156 157 return cast<SymbolExtent>(SD); 158 } 159 160 const SymbolMetadata* 161 SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T, 162 unsigned Count, const void *SymbolTag) { 163 164 llvm::FoldingSetNodeID profile; 165 SymbolMetadata::Profile(profile, R, S, T, Count, SymbolTag); 166 void *InsertPos; 167 SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); 168 if (!SD) { 169 SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>(); 170 new (SD) SymbolMetadata(SymbolCounter, R, S, T, Count, SymbolTag); 171 DataSet.InsertNode(SD, InsertPos); 172 ++SymbolCounter; 173 } 174 175 return cast<SymbolMetadata>(SD); 176 } 177 178 const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs, 179 BinaryOperator::Opcode op, 180 const llvm::APSInt& v, 181 QualType t) { 182 llvm::FoldingSetNodeID ID; 183 SymIntExpr::Profile(ID, lhs, op, v, t); 184 void *InsertPos; 185 SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); 186 187 if (!data) { 188 data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>(); 189 new (data) SymIntExpr(lhs, op, v, t); 190 DataSet.InsertNode(data, InsertPos); 191 } 192 193 return cast<SymIntExpr>(data); 194 } 195 196 const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs, 197 BinaryOperator::Opcode op, 198 const SymExpr *rhs, 199 QualType t) { 200 llvm::FoldingSetNodeID ID; 201 SymSymExpr::Profile(ID, lhs, op, rhs, t); 202 void *InsertPos; 203 SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos); 204 205 if (!data) { 206 data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>(); 207 new (data) SymSymExpr(lhs, op, rhs, t); 208 DataSet.InsertNode(data, InsertPos); 209 } 210 211 return cast<SymSymExpr>(data); 212 } 213 214 QualType SymbolConjured::getType(ASTContext&) const { 215 return T; 216 } 217 218 QualType SymbolDerived::getType(ASTContext &Ctx) const { 219 return R->getValueType(); 220 } 221 222 QualType SymbolExtent::getType(ASTContext &Ctx) const { 223 return Ctx.getSizeType(); 224 } 225 226 QualType SymbolMetadata::getType(ASTContext&) const { 227 return T; 228 } 229 230 QualType SymbolRegionValue::getType(ASTContext &C) const { 231 return R->getValueType(); 232 } 233 234 SymbolManager::~SymbolManager() { 235 for (SymbolDependTy::const_iterator I = SymbolDependencies.begin(), 236 E = SymbolDependencies.end(); I != E; ++I) { 237 delete I->second; 238 } 239 240 } 241 242 bool SymbolManager::canSymbolicate(QualType T) { 243 T = T.getCanonicalType(); 244 245 if (Loc::isLocType(T)) 246 return true; 247 248 if (T->isIntegerType()) 249 return T->isScalarType(); 250 251 if (T->isRecordType() && !T->isUnionType()) 252 return true; 253 254 return false; 255 } 256 257 void SymbolManager::addSymbolDependency(const SymbolRef Primary, 258 const SymbolRef Dependent) { 259 SymbolDependTy::iterator I = SymbolDependencies.find(Primary); 260 SymbolRefSmallVectorTy *dependencies = 0; 261 if (I == SymbolDependencies.end()) { 262 dependencies = new SymbolRefSmallVectorTy(); 263 SymbolDependencies[Primary] = dependencies; 264 } else { 265 dependencies = I->second; 266 } 267 dependencies->push_back(Dependent); 268 } 269 270 const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols( 271 const SymbolRef Primary) { 272 SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary); 273 if (I == SymbolDependencies.end()) 274 return 0; 275 return I->second; 276 } 277 278 void SymbolReaper::markDependentsLive(SymbolRef sym) { 279 // Do not mark dependents more then once. 280 SymbolMapTy::iterator LI = TheLiving.find(sym); 281 assert(LI != TheLiving.end() && "The primary symbol is not live."); 282 if (LI->second == HaveMarkedDependents) 283 return; 284 LI->second = HaveMarkedDependents; 285 286 if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) { 287 for (SymbolRefSmallVectorTy::const_iterator I = Deps->begin(), 288 E = Deps->end(); I != E; ++I) { 289 if (TheLiving.find(*I) != TheLiving.end()) 290 continue; 291 markLive(*I); 292 } 293 } 294 } 295 296 void SymbolReaper::markLive(SymbolRef sym) { 297 TheLiving[sym] = NotProcessed; 298 TheDead.erase(sym); 299 markDependentsLive(sym); 300 } 301 302 void SymbolReaper::markLive(const MemRegion *region) { 303 RegionRoots.insert(region); 304 } 305 306 void SymbolReaper::markInUse(SymbolRef sym) { 307 if (isa<SymbolMetadata>(sym)) 308 MetadataInUse.insert(sym); 309 } 310 311 bool SymbolReaper::maybeDead(SymbolRef sym) { 312 if (isLive(sym)) 313 return false; 314 315 TheDead.insert(sym); 316 return true; 317 } 318 319 bool SymbolReaper::isLiveRegion(const MemRegion *MR) { 320 if (RegionRoots.count(MR)) 321 return true; 322 323 MR = MR->getBaseRegion(); 324 325 if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) 326 return isLive(SR->getSymbol()); 327 328 if (const VarRegion *VR = dyn_cast<VarRegion>(MR)) 329 return isLive(VR, true); 330 331 // FIXME: This is a gross over-approximation. What we really need is a way to 332 // tell if anything still refers to this region. Unlike SymbolicRegions, 333 // AllocaRegions don't have associated symbols, though, so we don't actually 334 // have a way to track their liveness. 335 if (isa<AllocaRegion>(MR)) 336 return true; 337 338 if (isa<CXXThisRegion>(MR)) 339 return true; 340 341 if (isa<MemSpaceRegion>(MR)) 342 return true; 343 344 return false; 345 } 346 347 bool SymbolReaper::isLive(SymbolRef sym) { 348 if (TheLiving.count(sym)) { 349 markDependentsLive(sym); 350 return true; 351 } 352 353 if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) { 354 if (isLive(derived->getParentSymbol())) { 355 markLive(sym); 356 return true; 357 } 358 return false; 359 } 360 361 if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) { 362 if (isLiveRegion(extent->getRegion())) { 363 markLive(sym); 364 return true; 365 } 366 return false; 367 } 368 369 if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) { 370 if (MetadataInUse.count(sym)) { 371 if (isLiveRegion(metadata->getRegion())) { 372 markLive(sym); 373 MetadataInUse.erase(sym); 374 return true; 375 } 376 } 377 return false; 378 } 379 380 // Interogate the symbol. It may derive from an input value to 381 // the analyzed function/method. 382 return isa<SymbolRegionValue>(sym); 383 } 384 385 bool SymbolReaper::isLive(const Stmt *ExprVal) const { 386 return LCtx->getAnalysisContext()->getRelaxedLiveVariables()-> 387 isLive(Loc, ExprVal); 388 } 389 390 bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{ 391 const StackFrameContext *VarContext = VR->getStackFrame(); 392 const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame(); 393 394 if (VarContext == CurrentContext) { 395 if (LCtx->getAnalysisContext()->getRelaxedLiveVariables()-> 396 isLive(Loc, VR->getDecl())) 397 return true; 398 399 if (!includeStoreBindings) 400 return false; 401 402 unsigned &cachedQuery = 403 const_cast<SymbolReaper*>(this)->includedRegionCache[VR]; 404 405 if (cachedQuery) { 406 return cachedQuery == 1; 407 } 408 409 // Query the store to see if the region occurs in any live bindings. 410 if (Store store = reapedStore.getStore()) { 411 bool hasRegion = 412 reapedStore.getStoreManager().includedInBindings(store, VR); 413 cachedQuery = hasRegion ? 1 : 2; 414 return hasRegion; 415 } 416 417 return false; 418 } 419 420 return VarContext->isParentOf(CurrentContext); 421 } 422 423 SymbolVisitor::~SymbolVisitor() {} 424