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/ExprObjC.h" 15 #include "clang/Analysis/AnalysisContext.h" 16 #include "clang/Analysis/CFG.h" 17 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 18 19 using namespace clang; 20 using namespace ento; 21 22 SVal Environment::lookupExpr(const EnvironmentEntry &E) const { 23 const SVal* X = ExprBindings.lookup(E); 24 if (X) { 25 SVal V = *X; 26 return V; 27 } 28 return UnknownVal(); 29 } 30 31 SVal Environment::getSVal(const EnvironmentEntry &Entry, 32 SValBuilder& svalBuilder, 33 bool useOnlyDirectBindings) const { 34 35 if (useOnlyDirectBindings) { 36 // This branch is rarely taken, but can be exercised by 37 // checkers that explicitly bind values to arbitrary 38 // expressions. It is crucial that we do not ignore any 39 // expression here, and do a direct lookup. 40 return lookupExpr(Entry); 41 } 42 43 const Stmt *E = Entry.getStmt(); 44 const LocationContext *LCtx = Entry.getLocationContext(); 45 46 for (;;) { 47 if (const Expr *Ex = dyn_cast<Expr>(E)) 48 E = Ex->IgnoreParens(); 49 50 switch (E->getStmtClass()) { 51 case Stmt::AddrLabelExprClass: 52 return svalBuilder.makeLoc(cast<AddrLabelExpr>(E)); 53 case Stmt::OpaqueValueExprClass: { 54 const OpaqueValueExpr *ope = cast<OpaqueValueExpr>(E); 55 E = ope->getSourceExpr(); 56 continue; 57 } 58 case Stmt::ParenExprClass: 59 case Stmt::GenericSelectionExprClass: 60 llvm_unreachable("ParenExprs and GenericSelectionExprs should " 61 "have been handled by IgnoreParens()"); 62 return UnknownVal(); 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 94 // Handle all other Stmt* using a lookup. 95 default: 96 break; 97 }; 98 break; 99 } 100 return lookupExpr(EnvironmentEntry(E, LCtx)); 101 } 102 103 Environment EnvironmentManager::bindExpr(Environment Env, 104 const EnvironmentEntry &E, 105 SVal V, 106 bool Invalidate) { 107 if (V.isUnknown()) { 108 if (Invalidate) 109 return Environment(F.remove(Env.ExprBindings, E)); 110 else 111 return Env; 112 } 113 return Environment(F.add(Env.ExprBindings, E, V)); 114 } 115 116 static inline EnvironmentEntry MakeLocation(const EnvironmentEntry &E) { 117 const Stmt *S = E.getStmt(); 118 S = (const Stmt*) (((uintptr_t) S) | 0x1); 119 return EnvironmentEntry(S, E.getLocationContext()); 120 } 121 122 Environment EnvironmentManager::bindExprAndLocation(Environment Env, 123 const EnvironmentEntry &E, 124 SVal location, SVal V) { 125 return Environment(F.add(F.add(Env.ExprBindings, MakeLocation(E), location), 126 E, V)); 127 } 128 129 namespace { 130 class MarkLiveCallback : public SymbolVisitor { 131 SymbolReaper &SymReaper; 132 public: 133 MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} 134 bool VisitSymbol(SymbolRef sym) { SymReaper.markLive(sym); return true; } 135 }; 136 } // end anonymous namespace 137 138 // In addition to mapping from EnvironmentEntry - > SVals in the Environment, 139 // we also maintain a mapping from EnvironmentEntry -> SVals (locations) 140 // that were used during a load and store. 141 static inline bool IsLocation(const EnvironmentEntry &E) { 142 const Stmt *S = E.getStmt(); 143 return (bool) (((uintptr_t) S) & 0x1); 144 } 145 146 // removeDeadBindings: 147 // - Remove subexpression bindings. 148 // - Remove dead block expression bindings. 149 // - Keep live block expression bindings: 150 // - Mark their reachable symbols live in SymbolReaper, 151 // see ScanReachableSymbols. 152 // - Mark the region in DRoots if the binding is a loc::MemRegionVal. 153 Environment 154 EnvironmentManager::removeDeadBindings(Environment Env, 155 SymbolReaper &SymReaper, 156 const ProgramState *ST) { 157 158 // We construct a new Environment object entirely, as this is cheaper than 159 // individually removing all the subexpression bindings (which will greatly 160 // outnumber block-level expression bindings). 161 Environment NewEnv = getInitialEnvironment(); 162 163 SmallVector<std::pair<EnvironmentEntry, SVal>, 10> deferredLocations; 164 165 MarkLiveCallback CB(SymReaper); 166 ScanReachableSymbols RSScaner(ST, CB); 167 168 llvm::ImmutableMapRef<EnvironmentEntry,SVal> 169 EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(), 170 F.getTreeFactory()); 171 172 // Iterate over the block-expr bindings. 173 for (Environment::iterator I = Env.begin(), E = Env.end(); 174 I != E; ++I) { 175 176 const EnvironmentEntry &BlkExpr = I.getKey(); 177 // For recorded locations (used when evaluating loads and stores), we 178 // consider them live only when their associated normal expression is 179 // also live. 180 // NOTE: This assumes that loads/stores that evaluated to UnknownVal 181 // still have an entry in the map. 182 if (IsLocation(BlkExpr)) { 183 deferredLocations.push_back(std::make_pair(BlkExpr, I.getData())); 184 continue; 185 } 186 const SVal &X = I.getData(); 187 188 if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) { 189 // Copy the binding to the new map. 190 EBMapRef = EBMapRef.add(BlkExpr, X); 191 192 // If the block expr's value is a memory region, then mark that region. 193 if (isa<loc::MemRegionVal>(X)) { 194 const MemRegion *R = cast<loc::MemRegionVal>(X).getRegion(); 195 SymReaper.markLive(R); 196 } 197 198 // Mark all symbols in the block expr's value live. 199 RSScaner.scan(X); 200 continue; 201 } 202 203 // Otherwise the expression is dead with a couple exceptions. 204 // Do not misclean LogicalExpr or ConditionalOperator. It is dead at the 205 // beginning of itself, but we need its UndefinedVal to determine its 206 // SVal. 207 if (X.isUndef() && cast<UndefinedVal>(X).getData()) 208 EBMapRef = EBMapRef.add(BlkExpr, X); 209 } 210 211 // Go through he deferred locations and add them to the new environment if 212 // the correspond Stmt* is in the map as well. 213 for (SmallVectorImpl<std::pair<EnvironmentEntry, SVal> >::iterator 214 I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) { 215 const EnvironmentEntry &En = I->first; 216 const Stmt *S = (Stmt*) (((uintptr_t) En.getStmt()) & (uintptr_t) ~0x1); 217 if (EBMapRef.lookup(EnvironmentEntry(S, En.getLocationContext()))) 218 EBMapRef = EBMapRef.add(En, I->second); 219 } 220 221 NewEnv.ExprBindings = EBMapRef.asImmutableMap(); 222 return NewEnv; 223 } 224 225 void Environment::print(raw_ostream &Out, const char *NL, 226 const char *Sep) const { 227 printAux(Out, false, NL, Sep); 228 printAux(Out, true, NL, Sep); 229 } 230 231 void Environment::printAux(raw_ostream &Out, bool printLocations, 232 const char *NL, 233 const char *Sep) const{ 234 235 bool isFirst = true; 236 237 for (Environment::iterator I = begin(), E = end(); I != E; ++I) { 238 const EnvironmentEntry &En = I.getKey(); 239 if (IsLocation(En)) { 240 if (!printLocations) 241 continue; 242 } 243 else { 244 if (printLocations) 245 continue; 246 } 247 248 if (isFirst) { 249 Out << NL << NL 250 << (printLocations ? "Load/Store locations:" : "Expressions:") 251 << NL; 252 isFirst = false; 253 } else { 254 Out << NL; 255 } 256 257 const Stmt *S = En.getStmt(); 258 if (printLocations) { 259 S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1)); 260 } 261 262 Out << " (" << (void*) En.getLocationContext() << ',' << (void*) S << ") "; 263 LangOptions LO; // FIXME. 264 S->printPretty(Out, 0, PrintingPolicy(LO)); 265 Out << " : " << I.getData(); 266 } 267 } 268