Environment.cpp revision a93d0f280693b8418bc88cf7a8c93325f7fcf4c6
1//== Environment.cpp - Map from Stmt* to Locations/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 defined the Environment and EnvironmentManager classes. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/AST/ExprCXX.h" 15#include "clang/AST/ExprObjC.h" 16#include "clang/Analysis/AnalysisContext.h" 17#include "clang/Analysis/CFG.h" 18#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 19#include "llvm/Support/raw_ostream.h" 20 21using namespace clang; 22using namespace ento; 23 24static const Expr *ignoreTransparentExprs(const Expr *E) { 25 E = E->IgnoreParens(); 26 27 switch (E->getStmtClass()) { 28 case Stmt::OpaqueValueExprClass: 29 E = cast<OpaqueValueExpr>(E)->getSourceExpr(); 30 break; 31 case Stmt::ExprWithCleanupsClass: 32 E = cast<ExprWithCleanups>(E)->getSubExpr(); 33 break; 34 case Stmt::CXXBindTemporaryExprClass: 35 E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); 36 break; 37 case Stmt::SubstNonTypeTemplateParmExprClass: 38 E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(); 39 break; 40 case Stmt::CXXDefaultArgExprClass: 41 E = cast<CXXDefaultArgExpr>(E)->getExpr(); 42 break; 43 default: 44 // This is the base case: we can't look through more than we already have. 45 return E; 46 } 47 48 return ignoreTransparentExprs(E); 49} 50 51static const Stmt *ignoreTransparentExprs(const Stmt *S) { 52 if (const Expr *E = dyn_cast<Expr>(S)) 53 return ignoreTransparentExprs(E); 54 return S; 55} 56 57EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L) 58 : std::pair<const Stmt *, 59 const StackFrameContext *>(ignoreTransparentExprs(S), 60 L ? L->getCurrentStackFrame() : 0) {} 61 62SVal Environment::lookupExpr(const EnvironmentEntry &E) const { 63 const SVal* X = ExprBindings.lookup(E); 64 if (X) { 65 SVal V = *X; 66 return V; 67 } 68 return UnknownVal(); 69} 70 71SVal Environment::getSVal(const EnvironmentEntry &Entry, 72 SValBuilder& svalBuilder) const { 73 const Stmt *S = Entry.getStmt(); 74 const LocationContext *LCtx = Entry.getLocationContext(); 75 76 switch (S->getStmtClass()) { 77 case Stmt::CXXBindTemporaryExprClass: 78 case Stmt::CXXDefaultArgExprClass: 79 case Stmt::ExprWithCleanupsClass: 80 case Stmt::GenericSelectionExprClass: 81 case Stmt::OpaqueValueExprClass: 82 case Stmt::ParenExprClass: 83 case Stmt::SubstNonTypeTemplateParmExprClass: 84 llvm_unreachable("Should have been handled by ignoreTransparentExprs"); 85 86 case Stmt::AddrLabelExprClass: 87 return svalBuilder.makeLoc(cast<AddrLabelExpr>(S)); 88 89 case Stmt::CharacterLiteralClass: { 90 const CharacterLiteral *C = cast<CharacterLiteral>(S); 91 return svalBuilder.makeIntVal(C->getValue(), C->getType()); 92 } 93 94 case Stmt::CXXBoolLiteralExprClass: 95 return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(S)); 96 97 case Stmt::CXXScalarValueInitExprClass: 98 case Stmt::ImplicitValueInitExprClass: { 99 QualType Ty = cast<Expr>(S)->getType(); 100 return svalBuilder.makeZeroVal(Ty); 101 } 102 103 case Stmt::IntegerLiteralClass: 104 return svalBuilder.makeIntVal(cast<IntegerLiteral>(S)); 105 106 case Stmt::ObjCBoolLiteralExprClass: 107 return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(S)); 108 109 // For special C0xx nullptr case, make a null pointer SVal. 110 case Stmt::CXXNullPtrLiteralExprClass: 111 return svalBuilder.makeNull(); 112 113 case Stmt::ObjCStringLiteralClass: { 114 MemRegionManager &MRMgr = svalBuilder.getRegionManager(); 115 const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(S); 116 return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL)); 117 } 118 119 case Stmt::StringLiteralClass: { 120 MemRegionManager &MRMgr = svalBuilder.getRegionManager(); 121 const StringLiteral *SL = cast<StringLiteral>(S); 122 return svalBuilder.makeLoc(MRMgr.getStringRegion(SL)); 123 } 124 125 case Stmt::ReturnStmtClass: { 126 const ReturnStmt *RS = cast<ReturnStmt>(S); 127 if (const Expr *RE = RS->getRetValue()) 128 return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder); 129 return UndefinedVal(); 130 } 131 132 // Handle all other Stmt* using a lookup. 133 default: 134 break; 135 } 136 137 return lookupExpr(EnvironmentEntry(S, LCtx)); 138} 139 140Environment EnvironmentManager::bindExpr(Environment Env, 141 const EnvironmentEntry &E, 142 SVal V, 143 bool Invalidate) { 144 if (V.isUnknown()) { 145 if (Invalidate) 146 return Environment(F.remove(Env.ExprBindings, E)); 147 else 148 return Env; 149 } 150 return Environment(F.add(Env.ExprBindings, E, V)); 151} 152 153EnvironmentEntry EnvironmentEntry::makeLocation() const { 154 EnvironmentEntry Result = *this; 155 reinterpret_cast<uintptr_t &>(Result.first) |= 0x1; 156 return Result; 157} 158 159Environment EnvironmentManager::bindExprAndLocation(Environment Env, 160 const EnvironmentEntry &E, 161 SVal location, SVal V) { 162 return Environment(F.add(F.add(Env.ExprBindings, E.makeLocation(), location), 163 E, V)); 164} 165 166namespace { 167class MarkLiveCallback : public SymbolVisitor { 168 SymbolReaper &SymReaper; 169public: 170 MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} 171 bool VisitSymbol(SymbolRef sym) { 172 SymReaper.markLive(sym); 173 return true; 174 } 175 bool VisitMemRegion(const MemRegion *R) { 176 SymReaper.markLive(R); 177 return true; 178 } 179}; 180} // end anonymous namespace 181 182// In addition to mapping from EnvironmentEntry - > SVals in the Environment, 183// we also maintain a mapping from EnvironmentEntry -> SVals (locations) 184// that were used during a load and store. 185static inline bool IsLocation(const EnvironmentEntry &E) { 186 const Stmt *S = E.getStmt(); 187 return (bool) (((uintptr_t) S) & 0x1); 188} 189 190// removeDeadBindings: 191// - Remove subexpression bindings. 192// - Remove dead block expression bindings. 193// - Keep live block expression bindings: 194// - Mark their reachable symbols live in SymbolReaper, 195// see ScanReachableSymbols. 196// - Mark the region in DRoots if the binding is a loc::MemRegionVal. 197Environment 198EnvironmentManager::removeDeadBindings(Environment Env, 199 SymbolReaper &SymReaper, 200 ProgramStateRef ST) { 201 202 // We construct a new Environment object entirely, as this is cheaper than 203 // individually removing all the subexpression bindings (which will greatly 204 // outnumber block-level expression bindings). 205 Environment NewEnv = getInitialEnvironment(); 206 207 SmallVector<std::pair<EnvironmentEntry, SVal>, 10> deferredLocations; 208 209 MarkLiveCallback CB(SymReaper); 210 ScanReachableSymbols RSScaner(ST, CB); 211 212 llvm::ImmutableMapRef<EnvironmentEntry,SVal> 213 EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(), 214 F.getTreeFactory()); 215 216 // Iterate over the block-expr bindings. 217 for (Environment::iterator I = Env.begin(), E = Env.end(); 218 I != E; ++I) { 219 220 const EnvironmentEntry &BlkExpr = I.getKey(); 221 // For recorded locations (used when evaluating loads and stores), we 222 // consider them live only when their associated normal expression is 223 // also live. 224 // NOTE: This assumes that loads/stores that evaluated to UnknownVal 225 // still have an entry in the map. 226 if (IsLocation(BlkExpr)) { 227 deferredLocations.push_back(std::make_pair(BlkExpr, I.getData())); 228 continue; 229 } 230 const SVal &X = I.getData(); 231 232 if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) { 233 // Copy the binding to the new map. 234 EBMapRef = EBMapRef.add(BlkExpr, X); 235 236 // If the block expr's value is a memory region, then mark that region. 237 if (isa<loc::MemRegionVal>(X)) { 238 const MemRegion *R = cast<loc::MemRegionVal>(X).getRegion(); 239 SymReaper.markLive(R); 240 } 241 242 // Mark all symbols in the block expr's value live. 243 RSScaner.scan(X); 244 continue; 245 } else { 246 SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); 247 for (; SI != SE; ++SI) 248 SymReaper.maybeDead(*SI); 249 } 250 } 251 252 // Go through he deferred locations and add them to the new environment if 253 // the correspond Stmt* is in the map as well. 254 for (SmallVectorImpl<std::pair<EnvironmentEntry, SVal> >::iterator 255 I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) { 256 const EnvironmentEntry &En = I->first; 257 const Stmt *S = (Stmt*) (((uintptr_t) En.getStmt()) & (uintptr_t) ~0x1); 258 if (EBMapRef.lookup(EnvironmentEntry(S, En.getLocationContext()))) 259 EBMapRef = EBMapRef.add(En, I->second); 260 } 261 262 NewEnv.ExprBindings = EBMapRef.asImmutableMap(); 263 return NewEnv; 264} 265 266void Environment::print(raw_ostream &Out, const char *NL, 267 const char *Sep) const { 268 printAux(Out, false, NL, Sep); 269 printAux(Out, true, NL, Sep); 270} 271 272void Environment::printAux(raw_ostream &Out, bool printLocations, 273 const char *NL, 274 const char *Sep) const{ 275 276 bool isFirst = true; 277 278 for (Environment::iterator I = begin(), E = end(); I != E; ++I) { 279 const EnvironmentEntry &En = I.getKey(); 280 if (IsLocation(En)) { 281 if (!printLocations) 282 continue; 283 } 284 else { 285 if (printLocations) 286 continue; 287 } 288 289 if (isFirst) { 290 Out << NL << NL 291 << (printLocations ? "Load/Store locations:" : "Expressions:") 292 << NL; 293 isFirst = false; 294 } else { 295 Out << NL; 296 } 297 298 const Stmt *S = En.getStmt(); 299 if (printLocations) { 300 S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1)); 301 } 302 303 Out << " (" << (const void*) En.getLocationContext() << ',' 304 << (const void*) S << ") "; 305 LangOptions LO; // FIXME. 306 S->printPretty(Out, 0, PrintingPolicy(LO)); 307 Out << " : " << I.getData(); 308 } 309} 310