Environment.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. //===- Environment.cpp - Map from Stmt* to Locations/Values ---------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file defined the Environment and EnvironmentManager classes.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
  13. #include "clang/AST/Expr.h"
  14. #include "clang/AST/ExprCXX.h"
  15. #include "clang/AST/PrettyPrinter.h"
  16. #include "clang/AST/Stmt.h"
  17. #include "clang/Analysis/AnalysisDeclContext.h"
  18. #include "clang/Basic/LLVM.h"
  19. #include "clang/Basic/LangOptions.h"
  20. #include "clang/Basic/JsonSupport.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::ConstantExprClass:
  86. case Stmt::ParenExprClass:
  87. case Stmt::SubstNonTypeTemplateParmExprClass:
  88. llvm_unreachable("Should have been handled by ignoreTransparentExprs");
  89. case Stmt::AddrLabelExprClass:
  90. case Stmt::CharacterLiteralClass:
  91. case Stmt::CXXBoolLiteralExprClass:
  92. case Stmt::CXXScalarValueInitExprClass:
  93. case Stmt::ImplicitValueInitExprClass:
  94. case Stmt::IntegerLiteralClass:
  95. case Stmt::ObjCBoolLiteralExprClass:
  96. case Stmt::CXXNullPtrLiteralExprClass:
  97. case Stmt::ObjCStringLiteralClass:
  98. case Stmt::StringLiteralClass:
  99. case Stmt::TypeTraitExprClass:
  100. // Known constants; defer to SValBuilder.
  101. return svalBuilder.getConstantVal(cast<Expr>(S)).getValue();
  102. case Stmt::ReturnStmtClass: {
  103. const auto *RS = cast<ReturnStmt>(S);
  104. if (const Expr *RE = RS->getRetValue())
  105. return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
  106. return UndefinedVal();
  107. }
  108. // Handle all other Stmt* using a lookup.
  109. default:
  110. return lookupExpr(EnvironmentEntry(S, LCtx));
  111. }
  112. }
  113. Environment EnvironmentManager::bindExpr(Environment Env,
  114. const EnvironmentEntry &E,
  115. SVal V,
  116. bool Invalidate) {
  117. if (V.isUnknown()) {
  118. if (Invalidate)
  119. return Environment(F.remove(Env.ExprBindings, E));
  120. else
  121. return Env;
  122. }
  123. return Environment(F.add(Env.ExprBindings, E, V));
  124. }
  125. namespace {
  126. class MarkLiveCallback final : public SymbolVisitor {
  127. SymbolReaper &SymReaper;
  128. public:
  129. MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
  130. bool VisitSymbol(SymbolRef sym) override {
  131. SymReaper.markLive(sym);
  132. return true;
  133. }
  134. bool VisitMemRegion(const MemRegion *R) override {
  135. SymReaper.markLive(R);
  136. return true;
  137. }
  138. };
  139. } // namespace
  140. // removeDeadBindings:
  141. // - Remove subexpression bindings.
  142. // - Remove dead block expression bindings.
  143. // - Keep live block expression bindings:
  144. // - Mark their reachable symbols live in SymbolReaper,
  145. // see ScanReachableSymbols.
  146. // - Mark the region in DRoots if the binding is a loc::MemRegionVal.
  147. Environment
  148. EnvironmentManager::removeDeadBindings(Environment Env,
  149. SymbolReaper &SymReaper,
  150. ProgramStateRef ST) {
  151. // We construct a new Environment object entirely, as this is cheaper than
  152. // individually removing all the subexpression bindings (which will greatly
  153. // outnumber block-level expression bindings).
  154. Environment NewEnv = getInitialEnvironment();
  155. MarkLiveCallback CB(SymReaper);
  156. ScanReachableSymbols RSScaner(ST, CB);
  157. llvm::ImmutableMapRef<EnvironmentEntry, SVal>
  158. EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
  159. F.getTreeFactory());
  160. // Iterate over the block-expr bindings.
  161. for (Environment::iterator I = Env.begin(), E = Env.end();
  162. I != E; ++I) {
  163. const EnvironmentEntry &BlkExpr = I.getKey();
  164. const SVal &X = I.getData();
  165. if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
  166. // Copy the binding to the new map.
  167. EBMapRef = EBMapRef.add(BlkExpr, X);
  168. // Mark all symbols in the block expr's value live.
  169. RSScaner.scan(X);
  170. }
  171. }
  172. NewEnv.ExprBindings = EBMapRef.asImmutableMap();
  173. return NewEnv;
  174. }
  175. void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
  176. const LocationContext *LCtx, const char *NL,
  177. unsigned int Space, bool IsDot) const {
  178. Indent(Out, Space, IsDot) << "\"environment\": ";
  179. ++Space;
  180. if (ExprBindings.isEmpty()) {
  181. Out << "null," << NL;
  182. return;
  183. }
  184. if (!LCtx) {
  185. // Find the freshest location context.
  186. llvm::SmallPtrSet<const LocationContext *, 16> FoundContexts;
  187. for (const auto &I : *this) {
  188. const LocationContext *LC = I.first.getLocationContext();
  189. if (FoundContexts.count(LC) == 0) {
  190. // This context is fresher than all other contexts so far.
  191. LCtx = LC;
  192. for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent())
  193. FoundContexts.insert(LCI);
  194. }
  195. }
  196. }
  197. assert(LCtx);
  198. Out << '[' << NL; // Start of Environment.
  199. PrintingPolicy PP = Ctx.getPrintingPolicy();
  200. LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
  201. // LCtx items begin
  202. bool HasItem = false;
  203. unsigned int InnerSpace = Space + 1;
  204. // Store the last ExprBinding which we will print.
  205. BindingsTy::iterator LastI = ExprBindings.end();
  206. for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
  207. ++I) {
  208. if (I->first.getLocationContext() != LC)
  209. continue;
  210. if (!HasItem) {
  211. HasItem = true;
  212. Out << '[' << NL;
  213. }
  214. const Stmt *S = I->first.getStmt();
  215. assert(S != nullptr && "Expected non-null Stmt");
  216. LastI = I;
  217. }
  218. for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
  219. ++I) {
  220. if (I->first.getLocationContext() != LC)
  221. continue;
  222. const Stmt *S = I->first.getStmt();
  223. Indent(Out, InnerSpace, IsDot)
  224. << "{ \"lctx_id\": " << LC->getID()
  225. << ", \"stmt_id\": " << S->getID(Ctx) << ", \"pretty\": ";
  226. S->printJson(Out, nullptr, PP, /*AddQuotes=*/true);
  227. Out << ", \"value\": \"" << I->second << "\" }";
  228. if (I != LastI)
  229. Out << ',';
  230. Out << NL;
  231. }
  232. if (HasItem)
  233. Indent(Out, --InnerSpace, IsDot) << ']';
  234. else
  235. Out << "null ";
  236. });
  237. Indent(Out, --Space, IsDot) << "]," << NL; // End of Environment.
  238. }