SValExplainer.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //== SValExplainer.h - Symbolic value explainer -----------------*- C++ -*--==//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // This file defines SValExplainer, a class for pretty-printing a
  15. // human-readable description of a symbolic value. For example,
  16. // "reg_$0<x>" is turned into "initial value of variable 'x'".
  17. //
  18. //===----------------------------------------------------------------------===//
  19. #ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
  20. #define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
  21. #include "clang/AST/Attr.h"
  22. #include "clang/AST/DeclCXX.h"
  23. #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
  24. #include "llvm/ADT/StringExtras.h"
  25. namespace clang {
  26. namespace ento {
  27. class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
  28. private:
  29. ASTContext &ACtx;
  30. std::string printStmt(const Stmt *S) {
  31. std::string Str;
  32. llvm::raw_string_ostream OS(Str);
  33. S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
  34. return Str;
  35. }
  36. bool isThisObject(const SymbolicRegion *R) {
  37. if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
  38. if (isa<CXXThisRegion>(S->getRegion()))
  39. return true;
  40. return false;
  41. }
  42. public:
  43. SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
  44. std::string VisitUnknownVal(UnknownVal V) {
  45. return "unknown value";
  46. }
  47. std::string VisitUndefinedVal(UndefinedVal V) {
  48. return "undefined value";
  49. }
  50. std::string VisitLocMemRegionVal(loc::MemRegionVal V) {
  51. const MemRegion *R = V.getRegion();
  52. // Avoid the weird "pointer to pointee of ...".
  53. if (auto SR = dyn_cast<SymbolicRegion>(R)) {
  54. // However, "pointer to 'this' object" is fine.
  55. if (!isThisObject(SR))
  56. return Visit(SR->getSymbol());
  57. }
  58. return "pointer to " + Visit(R);
  59. }
  60. std::string VisitLocConcreteInt(loc::ConcreteInt V) {
  61. const llvm::APSInt &I = V.getValue();
  62. std::string Str;
  63. llvm::raw_string_ostream OS(Str);
  64. OS << "concrete memory address '" << I << "'";
  65. return Str;
  66. }
  67. std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
  68. return Visit(V.getSymbol());
  69. }
  70. std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
  71. const llvm::APSInt &I = V.getValue();
  72. std::string Str;
  73. llvm::raw_string_ostream OS(Str);
  74. OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
  75. << "-bit integer '" << I << "'";
  76. return Str;
  77. }
  78. std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
  79. return "lazily frozen compound value of " + Visit(V.getRegion());
  80. }
  81. std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
  82. const MemRegion *R = S->getRegion();
  83. // Special handling for argument values.
  84. if (auto V = dyn_cast<VarRegion>(R))
  85. if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
  86. return "argument '" + D->getQualifiedNameAsString() + "'";
  87. return "initial value of " + Visit(R);
  88. }
  89. std::string VisitSymbolConjured(const SymbolConjured *S) {
  90. return "symbol of type '" + S->getType().getAsString() +
  91. "' conjured at statement '" + printStmt(S->getStmt()) + "'";
  92. }
  93. std::string VisitSymbolDerived(const SymbolDerived *S) {
  94. return "value derived from (" + Visit(S->getParentSymbol()) +
  95. ") for " + Visit(S->getRegion());
  96. }
  97. std::string VisitSymbolExtent(const SymbolExtent *S) {
  98. return "extent of " + Visit(S->getRegion());
  99. }
  100. std::string VisitSymbolMetadata(const SymbolMetadata *S) {
  101. return "metadata of type '" + S->getType().getAsString() + "' tied to " +
  102. Visit(S->getRegion());
  103. }
  104. std::string VisitSymIntExpr(const SymIntExpr *S) {
  105. std::string Str;
  106. llvm::raw_string_ostream OS(Str);
  107. OS << "(" << Visit(S->getLHS()) << ") "
  108. << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
  109. << S->getRHS();
  110. return Str;
  111. }
  112. // TODO: IntSymExpr doesn't appear in practice.
  113. // Add the relevant code once it does.
  114. std::string VisitSymSymExpr(const SymSymExpr *S) {
  115. return "(" + Visit(S->getLHS()) + ") " +
  116. std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
  117. " (" + Visit(S->getRHS()) + ")";
  118. }
  119. // TODO: SymbolCast doesn't appear in practice.
  120. // Add the relevant code once it does.
  121. std::string VisitSymbolicRegion(const SymbolicRegion *R) {
  122. // Explain 'this' object here.
  123. // TODO: Explain CXXThisRegion itself, find a way to test it.
  124. if (isThisObject(R))
  125. return "'this' object";
  126. // Objective-C objects are not normal symbolic regions. At least,
  127. // they're always on the heap.
  128. if (R->getSymbol()->getType()
  129. .getCanonicalType()->getAs<ObjCObjectPointerType>())
  130. return "object at " + Visit(R->getSymbol());
  131. // Other heap-based symbolic regions are also special.
  132. if (isa<HeapSpaceRegion>(R->getMemorySpace()))
  133. return "heap segment that starts at " + Visit(R->getSymbol());
  134. return "pointee of " + Visit(R->getSymbol());
  135. }
  136. std::string VisitAllocaRegion(const AllocaRegion *R) {
  137. return "region allocated by '" + printStmt(R->getExpr()) + "'";
  138. }
  139. std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
  140. return "compound literal " + printStmt(R->getLiteralExpr());
  141. }
  142. std::string VisitStringRegion(const StringRegion *R) {
  143. return "string literal " + R->getString();
  144. }
  145. std::string VisitElementRegion(const ElementRegion *R) {
  146. std::string Str;
  147. llvm::raw_string_ostream OS(Str);
  148. OS << "element of type '" << R->getElementType().getAsString()
  149. << "' with index ";
  150. // For concrete index: omit type of the index integer.
  151. if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
  152. OS << I->getValue();
  153. else
  154. OS << "'" << Visit(R->getIndex()) << "'";
  155. OS << " of " + Visit(R->getSuperRegion());
  156. return Str;
  157. }
  158. std::string VisitNonParamVarRegion(const NonParamVarRegion *R) {
  159. const VarDecl *VD = R->getDecl();
  160. std::string Name = VD->getQualifiedNameAsString();
  161. if (isa<ParmVarDecl>(VD))
  162. return "parameter '" + Name + "'";
  163. else if (VD->hasAttr<BlocksAttr>())
  164. return "block variable '" + Name + "'";
  165. else if (VD->hasLocalStorage())
  166. return "local variable '" + Name + "'";
  167. else if (VD->isStaticLocal())
  168. return "static local variable '" + Name + "'";
  169. else if (VD->hasGlobalStorage())
  170. return "global variable '" + Name + "'";
  171. else
  172. llvm_unreachable("A variable is either local or global");
  173. }
  174. std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) {
  175. return "instance variable '" + R->getDecl()->getNameAsString() + "' of " +
  176. Visit(R->getSuperRegion());
  177. }
  178. std::string VisitFieldRegion(const FieldRegion *R) {
  179. return "field '" + R->getDecl()->getNameAsString() + "' of " +
  180. Visit(R->getSuperRegion());
  181. }
  182. std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
  183. return "temporary object constructed at statement '" +
  184. printStmt(R->getExpr()) + "'";
  185. }
  186. std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
  187. return "base object '" + R->getDecl()->getQualifiedNameAsString() +
  188. "' inside " + Visit(R->getSuperRegion());
  189. }
  190. std::string VisitParamVarRegion(const ParamVarRegion *R) {
  191. std::string Str;
  192. llvm::raw_string_ostream OS(Str);
  193. const ParmVarDecl *PVD = R->getDecl();
  194. std::string Name = PVD->getQualifiedNameAsString();
  195. if (!Name.empty()) {
  196. OS << "parameter '" << Name << "'";
  197. return std::string(OS.str());
  198. }
  199. unsigned Index = R->getIndex() + 1;
  200. OS << Index << llvm::getOrdinalSuffix(Index) << " parameter of ";
  201. const Decl *Parent = R->getStackFrame()->getDecl();
  202. if (const auto *FD = dyn_cast<FunctionDecl>(Parent))
  203. OS << "function '" << FD->getQualifiedNameAsString() << "()'";
  204. else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent))
  205. OS << "C++ constructor '" << CD->getQualifiedNameAsString() << "()'";
  206. else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
  207. if (MD->isClassMethod())
  208. OS << "Objective-C method '+" << MD->getQualifiedNameAsString() << "'";
  209. else
  210. OS << "Objective-C method '-" << MD->getQualifiedNameAsString() << "'";
  211. } else if (isa<BlockDecl>(Parent)) {
  212. if (cast<BlockDecl>(Parent)->isConversionFromLambda())
  213. OS << "lambda";
  214. else
  215. OS << "block";
  216. }
  217. return std::string(OS.str());
  218. }
  219. std::string VisitSVal(SVal V) {
  220. std::string Str;
  221. llvm::raw_string_ostream OS(Str);
  222. OS << V;
  223. return "a value unsupported by the explainer: (" +
  224. std::string(OS.str()) + ")";
  225. }
  226. std::string VisitSymExpr(SymbolRef S) {
  227. std::string Str;
  228. llvm::raw_string_ostream OS(Str);
  229. S->dumpToStream(OS);
  230. return "a symbolic expression unsupported by the explainer: (" +
  231. std::string(OS.str()) + ")";
  232. }
  233. std::string VisitMemRegion(const MemRegion *R) {
  234. std::string Str;
  235. llvm::raw_string_ostream OS(Str);
  236. OS << R;
  237. return "a memory region unsupported by the explainer (" +
  238. std::string(OS.str()) + ")";
  239. }
  240. };
  241. } // end namespace ento
  242. } // end namespace clang
  243. #endif
  244. #ifdef __GNUC__
  245. #pragma GCC diagnostic pop
  246. #endif