Environment.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. //===- Environment.cpp - Map from Stmt* to Locations/Values ---------------===//
  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. #include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
  14. #include "clang/AST/Expr.h"
  15. #include "clang/AST/ExprCXX.h"
  16. #include "clang/AST/PrettyPrinter.h"
  17. #include "clang/AST/Stmt.h"
  18. #include "clang/Analysis/AnalysisDeclContext.h"
  19. #include "clang/Basic/LLVM.h"
  20. #include "clang/Basic/LangOptions.h"
  21. #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
  22. #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
  23. #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
  24. #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
  25. #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
  26. #include "llvm/ADT/ImmutableMap.h"
  27. #include "llvm/ADT/SmallPtrSet.h"
  28. #include "llvm/Support/Casting.h"
  29. #include "llvm/Support/ErrorHandling.h"
  30. #include "llvm/Support/raw_ostream.h"
  31. #include <cassert>
  32. using namespace clang;
  33. using namespace ento;
  34. static const Expr *ignoreTransparentExprs(const Expr *E) {
  35. E = E->IgnoreParens();
  36. switch (E->getStmtClass()) {
  37. case Stmt::OpaqueValueExprClass:
  38. E = cast<OpaqueValueExpr>(E)->getSourceExpr();
  39. break;
  40. case Stmt::ExprWithCleanupsClass:
  41. E = cast<ExprWithCleanups>(E)->getSubExpr();
  42. break;
  43. case Stmt::ConstantExprClass:
  44. E = cast<ConstantExpr>(E)->getSubExpr();
  45. break;
  46. case Stmt::CXXBindTemporaryExprClass:
  47. E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
  48. break;
  49. case Stmt::SubstNonTypeTemplateParmExprClass:
  50. E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
  51. break;
  52. default:
  53. // This is the base case: we can't look through more than we already have.
  54. return E;
  55. }
  56. return ignoreTransparentExprs(E);
  57. }
  58. static const Stmt *ignoreTransparentExprs(const Stmt *S) {
  59. if (const auto *E = dyn_cast<Expr>(S))
  60. return ignoreTransparentExprs(E);
  61. return S;
  62. }
  63. EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L)
  64. : std::pair<const Stmt *,
  65. const StackFrameContext *>(ignoreTransparentExprs(S),
  66. L ? L->getStackFrame()
  67. : nullptr) {}
  68. SVal Environment::lookupExpr(const EnvironmentEntry &E) const {
  69. const SVal* X = ExprBindings.lookup(E);
  70. if (X) {
  71. SVal V = *X;
  72. return V;
  73. }
  74. return UnknownVal();
  75. }
  76. SVal Environment::getSVal(const EnvironmentEntry &Entry,
  77. SValBuilder& svalBuilder) const {
  78. const Stmt *S = Entry.getStmt();
  79. const LocationContext *LCtx = Entry.getLocationContext();
  80. switch (S->getStmtClass()) {
  81. case Stmt::CXXBindTemporaryExprClass:
  82. case Stmt::ExprWithCleanupsClass:
  83. case Stmt::GenericSelectionExprClass:
  84. case Stmt::OpaqueValueExprClass:
  85. case Stmt::ParenExprClass:
  86. case Stmt::SubstNonTypeTemplateParmExprClass:
  87. llvm_unreachable("Should have been handled by ignoreTransparentExprs");
  88. case Stmt::AddrLabelExprClass:
  89. case Stmt::CharacterLiteralClass:
  90. case Stmt::CXXBoolLiteralExprClass:
  91. case Stmt::CXXScalarValueInitExprClass:
  92. case Stmt::ImplicitValueInitExprClass:
  93. case Stmt::IntegerLiteralClass:
  94. case Stmt::ObjCBoolLiteralExprClass:
  95. case Stmt::CXXNullPtrLiteralExprClass:
  96. case Stmt::ObjCStringLiteralClass:
  97. case Stmt::StringLiteralClass:
  98. case Stmt::TypeTraitExprClass:
  99. // Known constants; defer to SValBuilder.
  100. return svalBuilder.getConstantVal(cast<Expr>(S)).getValue();
  101. case Stmt::ReturnStmtClass: {
  102. const auto *RS = cast<ReturnStmt>(S);
  103. if (const Expr *RE = RS->getRetValue())
  104. return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
  105. return UndefinedVal();
  106. }
  107. // Handle all other Stmt* using a lookup.
  108. default:
  109. return lookupExpr(EnvironmentEntry(S, LCtx));
  110. }
  111. }
  112. Environment EnvironmentManager::bindExpr(Environment Env,
  113. const EnvironmentEntry &E,
  114. SVal V,
  115. bool Invalidate) {
  116. if (V.isUnknown()) {
  117. if (Invalidate)
  118. return Environment(F.remove(Env.ExprBindings, E));
  119. else
  120. return Env;
  121. }
  122. return Environment(F.add(Env.ExprBindings, E, V));
  123. }
  124. namespace {
  125. class MarkLiveCallback final : public SymbolVisitor {
  126. SymbolReaper &SymReaper;
  127. public:
  128. MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
  129. bool VisitSymbol(SymbolRef sym) override {
  130. SymReaper.markLive(sym);
  131. return true;
  132. }
  133. bool VisitMemRegion(const MemRegion *R) override {
  134. SymReaper.markLive(R);
  135. return true;
  136. }
  137. };
  138. } // namespace
  139. // removeDeadBindings:
  140. // - Remove subexpression bindings.
  141. // - Remove dead block expression bindings.
  142. // - Keep live block expression bindings:
  143. // - Mark their reachable symbols live in SymbolReaper,
  144. // see ScanReachableSymbols.
  145. // - Mark the region in DRoots if the binding is a loc::MemRegionVal.
  146. Environment
  147. EnvironmentManager::removeDeadBindings(Environment Env,
  148. SymbolReaper &SymReaper,
  149. ProgramStateRef ST) {
  150. // We construct a new Environment object entirely, as this is cheaper than
  151. // individually removing all the subexpression bindings (which will greatly
  152. // outnumber block-level expression bindings).
  153. Environment NewEnv = getInitialEnvironment();
  154. MarkLiveCallback CB(SymReaper);
  155. ScanReachableSymbols RSScaner(ST, CB);
  156. llvm::ImmutableMapRef<EnvironmentEntry, SVal>
  157. EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
  158. F.getTreeFactory());
  159. // Iterate over the block-expr bindings.
  160. for (Environment::iterator I = Env.begin(), E = Env.end();
  161. I != E; ++I) {
  162. const EnvironmentEntry &BlkExpr = I.getKey();
  163. const SVal &X = I.getData();
  164. if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
  165. // Copy the binding to the new map.
  166. EBMapRef = EBMapRef.add(BlkExpr, X);
  167. // Mark all symbols in the block expr's value live.
  168. RSScaner.scan(X);
  169. continue;
  170. } else {
  171. SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
  172. for (; SI != SE; ++SI)
  173. SymReaper.maybeDead(*SI);
  174. }
  175. }
  176. NewEnv.ExprBindings = EBMapRef.asImmutableMap();
  177. return NewEnv;
  178. }
  179. void Environment::print(raw_ostream &Out, const char *NL,
  180. const char *Sep,
  181. const ASTContext &Context,
  182. const LocationContext *WithLC) const {
  183. if (ExprBindings.isEmpty())
  184. return;
  185. if (!WithLC) {
  186. // Find the freshest location context.
  187. llvm::SmallPtrSet<const LocationContext *, 16> FoundContexts;
  188. for (auto I : *this) {
  189. const LocationContext *LC = I.first.getLocationContext();
  190. if (FoundContexts.count(LC) == 0) {
  191. // This context is fresher than all other contexts so far.
  192. WithLC = LC;
  193. for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent())
  194. FoundContexts.insert(LCI);
  195. }
  196. }
  197. }
  198. assert(WithLC);
  199. PrintingPolicy PP = Context.getPrintingPolicy();
  200. Out << NL << "Expressions by stack frame:" << NL;
  201. WithLC->dumpStack(Out, "", NL, Sep, [&](const LocationContext *LC) {
  202. for (auto I : ExprBindings) {
  203. if (I.first.getLocationContext() != LC)
  204. continue;
  205. const Stmt *S = I.first.getStmt();
  206. assert(S != nullptr && "Expected non-null Stmt");
  207. Out << "(LC" << LC->getID() << ", S" << S->getID(Context) << ") ";
  208. S->printPretty(Out, /*Helper=*/nullptr, PP);
  209. Out << " : " << I.second << NL;
  210. }
  211. });
  212. }