Environment.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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. case Stmt::SizeOfPackExprClass:
  101. // Known constants; defer to SValBuilder.
  102. return svalBuilder.getConstantVal(cast<Expr>(S)).getValue();
  103. case Stmt::ReturnStmtClass: {
  104. const auto *RS = cast<ReturnStmt>(S);
  105. if (const Expr *RE = RS->getRetValue())
  106. return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
  107. return UndefinedVal();
  108. }
  109. // Handle all other Stmt* using a lookup.
  110. default:
  111. return lookupExpr(EnvironmentEntry(S, LCtx));
  112. }
  113. }
  114. Environment EnvironmentManager::bindExpr(Environment Env,
  115. const EnvironmentEntry &E,
  116. SVal V,
  117. bool Invalidate) {
  118. if (V.isUnknown()) {
  119. if (Invalidate)
  120. return Environment(F.remove(Env.ExprBindings, E));
  121. else
  122. return Env;
  123. }
  124. return Environment(F.add(Env.ExprBindings, E, V));
  125. }
  126. namespace {
  127. class MarkLiveCallback final : public SymbolVisitor {
  128. SymbolReaper &SymReaper;
  129. public:
  130. MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
  131. bool VisitSymbol(SymbolRef sym) override {
  132. SymReaper.markLive(sym);
  133. return true;
  134. }
  135. bool VisitMemRegion(const MemRegion *R) override {
  136. SymReaper.markLive(R);
  137. return true;
  138. }
  139. };
  140. } // namespace
  141. // removeDeadBindings:
  142. // - Remove subexpression bindings.
  143. // - Remove dead block expression bindings.
  144. // - Keep live block expression bindings:
  145. // - Mark their reachable symbols live in SymbolReaper,
  146. // see ScanReachableSymbols.
  147. // - Mark the region in DRoots if the binding is a loc::MemRegionVal.
  148. Environment
  149. EnvironmentManager::removeDeadBindings(Environment Env,
  150. SymbolReaper &SymReaper,
  151. ProgramStateRef ST) {
  152. // We construct a new Environment object entirely, as this is cheaper than
  153. // individually removing all the subexpression bindings (which will greatly
  154. // outnumber block-level expression bindings).
  155. Environment NewEnv = getInitialEnvironment();
  156. MarkLiveCallback CB(SymReaper);
  157. ScanReachableSymbols RSScaner(ST, CB);
  158. llvm::ImmutableMapRef<EnvironmentEntry, SVal>
  159. EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(),
  160. F.getTreeFactory());
  161. // Iterate over the block-expr bindings.
  162. for (Environment::iterator I = Env.begin(), E = Env.end();
  163. I != E; ++I) {
  164. const EnvironmentEntry &BlkExpr = I.getKey();
  165. const SVal &X = I.getData();
  166. if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
  167. // Copy the binding to the new map.
  168. EBMapRef = EBMapRef.add(BlkExpr, X);
  169. // Mark all symbols in the block expr's value live.
  170. RSScaner.scan(X);
  171. }
  172. }
  173. NewEnv.ExprBindings = EBMapRef.asImmutableMap();
  174. return NewEnv;
  175. }
  176. void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
  177. const LocationContext *LCtx, const char *NL,
  178. unsigned int Space, bool IsDot) const {
  179. Indent(Out, Space, IsDot) << "\"environment\": ";
  180. if (ExprBindings.isEmpty()) {
  181. Out << "null," << NL;
  182. return;
  183. }
  184. ++Space;
  185. if (!LCtx) {
  186. // Find the freshest location context.
  187. llvm::SmallPtrSet<const LocationContext *, 16> FoundContexts;
  188. for (const 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. LCtx = LC;
  193. for (const LocationContext *LCI = LC; LCI; LCI = LCI->getParent())
  194. FoundContexts.insert(LCI);
  195. }
  196. }
  197. }
  198. assert(LCtx);
  199. Out << "{ \"pointer\": \"" << (const void *)LCtx->getStackFrame()
  200. << "\", \"items\": [" << NL;
  201. PrintingPolicy PP = Ctx.getPrintingPolicy();
  202. LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
  203. // LCtx items begin
  204. bool HasItem = false;
  205. unsigned int InnerSpace = Space + 1;
  206. // Store the last ExprBinding which we will print.
  207. BindingsTy::iterator LastI = ExprBindings.end();
  208. for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
  209. ++I) {
  210. if (I->first.getLocationContext() != LC)
  211. continue;
  212. if (!HasItem) {
  213. HasItem = true;
  214. Out << '[' << NL;
  215. }
  216. const Stmt *S = I->first.getStmt();
  217. (void)S;
  218. assert(S != nullptr && "Expected non-null Stmt");
  219. LastI = I;
  220. }
  221. for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
  222. ++I) {
  223. if (I->first.getLocationContext() != LC)
  224. continue;
  225. const Stmt *S = I->first.getStmt();
  226. Indent(Out, InnerSpace, IsDot)
  227. << "{ \"stmt_id\": " << S->getID(Ctx) << ", \"pretty\": ";
  228. S->printJson(Out, nullptr, PP, /*AddQuotes=*/true);
  229. Out << ", \"value\": ";
  230. I->second.printJson(Out, /*AddQuotes=*/true);
  231. Out << " }";
  232. if (I != LastI)
  233. Out << ',';
  234. Out << NL;
  235. }
  236. if (HasItem)
  237. Indent(Out, --InnerSpace, IsDot) << ']';
  238. else
  239. Out << "null ";
  240. });
  241. Indent(Out, --Space, IsDot) << "]}," << NL;
  242. }