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 21 using namespace clang; 22 using namespace ento; 23 24 static 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 default: 41 // This is the base case: we can't look through more than we already have. 42 return E; 43 } 44 45 return ignoreTransparentExprs(E); 46 } 47 48 static const Stmt *ignoreTransparentExprs(const Stmt *S) { 49 if (const Expr *E = dyn_cast<Expr>(S)) 50 return ignoreTransparentExprs(E); 51 return S; 52 } 53 54 EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L) 55 : std::pair<const Stmt *, 56 const StackFrameContext *>(ignoreTransparentExprs(S), 57 L ? L->getCurrentStackFrame() : 0) {} 58 59 SVal Environment::lookupExpr(const EnvironmentEntry &E) const { 60 const SVal* X = ExprBindings.lookup(E); 61 if (X) { 62 SVal V = *X; 63 return V; 64 } 65 return UnknownVal(); 66 } 67 68 SVal Environment::getSVal(const EnvironmentEntry &Entry, 69 SValBuilder& svalBuilder) const { 70 const Stmt *S = Entry.getStmt(); 71 const LocationContext *LCtx = Entry.getLocationContext(); 72 73 switch (S->getStmtClass()) { 74 case Stmt::CXXBindTemporaryExprClass: 75 case Stmt::ExprWithCleanupsClass: 76 case Stmt::GenericSelectionExprClass: 77 case Stmt::OpaqueValueExprClass: 78 case Stmt::ParenExprClass: 79 case Stmt::SubstNonTypeTemplateParmExprClass: 80 llvm_unreachable("Should have been handled by ignoreTransparentExprs"); 81 82 case Stmt::AddrLabelExprClass: 83 case Stmt::CharacterLiteralClass: 84 case Stmt::CXXBoolLiteralExprClass: 85 case Stmt::CXXScalarValueInitExprClass: 86 case Stmt::ImplicitValueInitExprClass: 87 case Stmt::IntegerLiteralClass: 88 case Stmt::ObjCBoolLiteralExprClass: 89 case Stmt::CXXNullPtrLiteralExprClass: 90 case Stmt::ObjCStringLiteralClass: 91 case Stmt::StringLiteralClass: 92 // Known constants; defer to SValBuilder. 93 return svalBuilder.getConstantVal(cast<Expr>(S)).getValue(); 94 95 case Stmt::ReturnStmtClass: { 96 const ReturnStmt *RS = cast<ReturnStmt>(S); 97 if (const Expr *RE = RS->getRetValue()) 98 return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder); 99 return UndefinedVal(); 100 } 101 102 // Handle all other Stmt* using a lookup. 103 default: 104 return lookupExpr(EnvironmentEntry(S, LCtx)); 105 } 106 } 107 108 Environment EnvironmentManager::bindExpr(Environment Env, 109 const EnvironmentEntry &E, 110 SVal V, 111 bool Invalidate) { 112 if (V.isUnknown()) { 113 if (Invalidate) 114 return Environment(F.remove(Env.ExprBindings, E)); 115 else 116 return Env; 117 } 118 return Environment(F.add(Env.ExprBindings, E, V)); 119 } 120 121 namespace { 122 class MarkLiveCallback : public SymbolVisitor { 123 SymbolReaper &SymReaper; 124 public: 125 MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {} 126 bool VisitSymbol(SymbolRef sym) { 127 SymReaper.markLive(sym); 128 return true; 129 } 130 bool VisitMemRegion(const MemRegion *R) { 131 SymReaper.markLive(R); 132 return true; 133 } 134 }; 135 } // end anonymous namespace 136 137 // removeDeadBindings: 138 // - Remove subexpression bindings. 139 // - Remove dead block expression bindings. 140 // - Keep live block expression bindings: 141 // - Mark their reachable symbols live in SymbolReaper, 142 // see ScanReachableSymbols. 143 // - Mark the region in DRoots if the binding is a loc::MemRegionVal. 144 Environment 145 EnvironmentManager::removeDeadBindings(Environment Env, 146 SymbolReaper &SymReaper, 147 ProgramStateRef ST) { 148 149 // We construct a new Environment object entirely, as this is cheaper than 150 // individually removing all the subexpression bindings (which will greatly 151 // outnumber block-level expression bindings). 152 Environment NewEnv = getInitialEnvironment(); 153 154 MarkLiveCallback CB(SymReaper); 155 ScanReachableSymbols RSScaner(ST, CB); 156 157 llvm::ImmutableMapRef<EnvironmentEntry,SVal> 158 EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(), 159 F.getTreeFactory()); 160 161 // Iterate over the block-expr bindings. 162 for (Environment::iterator I = Env.begin(), E = Env.end(); 163 I != E; ++I) { 164 165 const EnvironmentEntry &BlkExpr = I.getKey(); 166 const SVal &X = I.getData(); 167 168 if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) { 169 // Copy the binding to the new map. 170 EBMapRef = EBMapRef.add(BlkExpr, X); 171 172 // If the block expr's value is a memory region, then mark that region. 173 if (Optional<loc::MemRegionVal> R = X.getAs<loc::MemRegionVal>()) 174 SymReaper.markLive(R->getRegion()); 175 176 // Mark all symbols in the block expr's value live. 177 RSScaner.scan(X); 178 continue; 179 } else { 180 SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); 181 for (; SI != SE; ++SI) 182 SymReaper.maybeDead(*SI); 183 } 184 } 185 186 NewEnv.ExprBindings = EBMapRef.asImmutableMap(); 187 return NewEnv; 188 } 189 190 void Environment::print(raw_ostream &Out, const char *NL, 191 const char *Sep) const { 192 bool isFirst = true; 193 194 for (Environment::iterator I = begin(), E = end(); I != E; ++I) { 195 const EnvironmentEntry &En = I.getKey(); 196 197 if (isFirst) { 198 Out << NL << NL 199 << "Expressions:" 200 << NL; 201 isFirst = false; 202 } else { 203 Out << NL; 204 } 205 206 const Stmt *S = En.getStmt(); 207 208 Out << " (" << (const void*) En.getLocationContext() << ',' 209 << (const void*) S << ") "; 210 LangOptions LO; // FIXME. 211 S->printPretty(Out, 0, PrintingPolicy(LO)); 212 Out << " : " << I.getData(); 213 } 214 } 215