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 20 using namespace clang; 21 using namespace ento; 22 23 SVal 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 32 SVal 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::IntegerLiteralClass: { 75 // In C++, this expression may have been bound to a temporary object. 76 SVal const *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx)); 77 if (X) 78 return *X; 79 else 80 return svalBuilder.makeIntVal(cast<IntegerLiteral>(E)); 81 } 82 // For special C0xx nullptr case, make a null pointer SVal. 83 case Stmt::CXXNullPtrLiteralExprClass: 84 return svalBuilder.makeNull(); 85 case Stmt::ExprWithCleanupsClass: 86 E = cast<ExprWithCleanups>(E)->getSubExpr(); 87 continue; 88 case Stmt::CXXBindTemporaryExprClass: 89 E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); 90 continue; 91 case Stmt::ObjCPropertyRefExprClass: 92 return loc::ObjCPropRef(cast<ObjCPropertyRefExpr>(E)); 93 case Stmt::ReturnStmtClass: { 94 const ReturnStmt *RS = cast<ReturnStmt>(E); 95 if (const Expr *RE = RS->getRetValue()) { 96 E = RE; 97 continue; 98 } 99 return UndefinedVal(); 100 } 101 102 // Handle all other Stmt* using a lookup. 103 default: 104 break; 105 }; 106 break; 107 } 108 return lookupExpr(EnvironmentEntry(E, LCtx)); 109 } 110 111 Environment EnvironmentManager::bindExpr(Environment Env, 112 const EnvironmentEntry &E, 113 SVal V, 114 bool Invalidate) { 115 if (V.isUnknown()) { 116 if (Invalidate) 117 return Environment(F.remove(Env.ExprBindings, E)); 118 else 119 return Env; 120 } 121 return Environment(F.add(Env.ExprBindings, E, V)); 122 } 123 124 static inline EnvironmentEntry MakeLocation(const EnvironmentEntry &E) { 125 const Stmt *S = E.getStmt(); 126 S = (const Stmt*) (((uintptr_t) S) | 0x1); 127 return EnvironmentEntry(S, E.getLocationContext()); 128 } 129 130 Environment EnvironmentManager::bindExprAndLocation(Environment Env, 131 const EnvironmentEntry &E, 132 SVal location, SVal V) { 133 return Environment(F.add(F.add(Env.ExprBindings, MakeLocation(E), location), 134 E, V)); 135 } 136 137 namespace { 138 class MarkLiveCallback : public SymbolVisitor { 139 SymbolReaper &SymReaper; 140 public: 141 MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} 142 bool VisitSymbol(SymbolRef sym) { 143 SymReaper.markLive(sym); 144 return true; 145 } 146 bool VisitMemRegion(const MemRegion *R) { 147 SymReaper.markLive(R); 148 return true; 149 } 150 }; 151 } // end anonymous namespace 152 153 // In addition to mapping from EnvironmentEntry - > SVals in the Environment, 154 // we also maintain a mapping from EnvironmentEntry -> SVals (locations) 155 // that were used during a load and store. 156 static inline bool IsLocation(const EnvironmentEntry &E) { 157 const Stmt *S = E.getStmt(); 158 return (bool) (((uintptr_t) S) & 0x1); 159 } 160 161 // removeDeadBindings: 162 // - Remove subexpression bindings. 163 // - Remove dead block expression bindings. 164 // - Keep live block expression bindings: 165 // - Mark their reachable symbols live in SymbolReaper, 166 // see ScanReachableSymbols. 167 // - Mark the region in DRoots if the binding is a loc::MemRegionVal. 168 Environment 169 EnvironmentManager::removeDeadBindings(Environment Env, 170 SymbolReaper &SymReaper, 171 ProgramStateRef ST) { 172 173 // We construct a new Environment object entirely, as this is cheaper than 174 // individually removing all the subexpression bindings (which will greatly 175 // outnumber block-level expression bindings). 176 Environment NewEnv = getInitialEnvironment(); 177 178 SmallVector<std::pair<EnvironmentEntry, SVal>, 10> deferredLocations; 179 180 MarkLiveCallback CB(SymReaper); 181 ScanReachableSymbols RSScaner(ST, CB); 182 183 llvm::ImmutableMapRef<EnvironmentEntry,SVal> 184 EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(), 185 F.getTreeFactory()); 186 187 // Iterate over the block-expr bindings. 188 for (Environment::iterator I = Env.begin(), E = Env.end(); 189 I != E; ++I) { 190 191 const EnvironmentEntry &BlkExpr = I.getKey(); 192 // For recorded locations (used when evaluating loads and stores), we 193 // consider them live only when their associated normal expression is 194 // also live. 195 // NOTE: This assumes that loads/stores that evaluated to UnknownVal 196 // still have an entry in the map. 197 if (IsLocation(BlkExpr)) { 198 deferredLocations.push_back(std::make_pair(BlkExpr, I.getData())); 199 continue; 200 } 201 const SVal &X = I.getData(); 202 203 if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) { 204 // Copy the binding to the new map. 205 EBMapRef = EBMapRef.add(BlkExpr, X); 206 207 // If the block expr's value is a memory region, then mark that region. 208 if (isa<loc::MemRegionVal>(X)) { 209 const MemRegion *R = cast<loc::MemRegionVal>(X).getRegion(); 210 SymReaper.markLive(R); 211 } 212 213 // Mark all symbols in the block expr's value live. 214 RSScaner.scan(X); 215 continue; 216 } 217 218 // Otherwise the expression is dead with a couple exceptions. 219 // Do not misclean LogicalExpr or ConditionalOperator. It is dead at the 220 // beginning of itself, but we need its UndefinedVal to determine its 221 // SVal. 222 if (X.isUndef() && cast<UndefinedVal>(X).getData()) 223 EBMapRef = EBMapRef.add(BlkExpr, X); 224 } 225 226 // Go through he deferred locations and add them to the new environment if 227 // the correspond Stmt* is in the map as well. 228 for (SmallVectorImpl<std::pair<EnvironmentEntry, SVal> >::iterator 229 I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) { 230 const EnvironmentEntry &En = I->first; 231 const Stmt *S = (Stmt*) (((uintptr_t) En.getStmt()) & (uintptr_t) ~0x1); 232 if (EBMapRef.lookup(EnvironmentEntry(S, En.getLocationContext()))) 233 EBMapRef = EBMapRef.add(En, I->second); 234 } 235 236 NewEnv.ExprBindings = EBMapRef.asImmutableMap(); 237 return NewEnv; 238 } 239 240 void Environment::print(raw_ostream &Out, const char *NL, 241 const char *Sep) const { 242 printAux(Out, false, NL, Sep); 243 printAux(Out, true, NL, Sep); 244 } 245 246 void Environment::printAux(raw_ostream &Out, bool printLocations, 247 const char *NL, 248 const char *Sep) const{ 249 250 bool isFirst = true; 251 252 for (Environment::iterator I = begin(), E = end(); I != E; ++I) { 253 const EnvironmentEntry &En = I.getKey(); 254 if (IsLocation(En)) { 255 if (!printLocations) 256 continue; 257 } 258 else { 259 if (printLocations) 260 continue; 261 } 262 263 if (isFirst) { 264 Out << NL << NL 265 << (printLocations ? "Load/Store locations:" : "Expressions:") 266 << NL; 267 isFirst = false; 268 } else { 269 Out << NL; 270 } 271 272 const Stmt *S = En.getStmt(); 273 if (printLocations) { 274 S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1)); 275 } 276 277 Out << " (" << (void*) En.getLocationContext() << ',' << (void*) S << ") "; 278 LangOptions LO; // FIXME. 279 S->printPretty(Out, 0, PrintingPolicy(LO)); 280 Out << " : " << I.getData(); 281 } 282 } 283