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