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