AnalysisOrderChecker.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. //===- AnalysisOrderChecker - Print callbacks called ------------*- C++ -*-===//
  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 checker prints callbacks that are called during analysis.
  10. // This is required to ensure that callbacks are fired in order
  11. // and do not duplicate or get lost.
  12. // Feel free to extend this checker with any callback you need to check.
  13. //
  14. //===----------------------------------------------------------------------===//
  15. #include "clang/AST/ExprCXX.h"
  16. #include "clang/Analysis/CFGStmtMap.h"
  17. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  18. #include "clang/StaticAnalyzer/Core/Checker.h"
  19. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  20. #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
  21. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  22. #include "llvm/Support/ErrorHandling.h"
  23. using namespace clang;
  24. using namespace ento;
  25. namespace {
  26. class AnalysisOrderChecker
  27. : public Checker<
  28. check::PreStmt<CastExpr>, check::PostStmt<CastExpr>,
  29. check::PreStmt<ArraySubscriptExpr>,
  30. check::PostStmt<ArraySubscriptExpr>, check::PreStmt<CXXNewExpr>,
  31. check::PostStmt<CXXNewExpr>, check::PreStmt<CXXDeleteExpr>,
  32. check::PostStmt<CXXDeleteExpr>, check::PreStmt<CXXConstructExpr>,
  33. check::PostStmt<CXXConstructExpr>, check::PreStmt<OffsetOfExpr>,
  34. check::PostStmt<OffsetOfExpr>, check::PreCall, check::PostCall,
  35. check::EndFunction, check::EndAnalysis, check::NewAllocator,
  36. check::Bind, check::PointerEscape, check::RegionChanges,
  37. check::LiveSymbols, eval::Call> {
  38. bool isCallbackEnabled(const AnalyzerOptions &Opts,
  39. StringRef CallbackName) const {
  40. return Opts.getCheckerBooleanOption(this, "*") ||
  41. Opts.getCheckerBooleanOption(this, CallbackName);
  42. }
  43. bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const {
  44. AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions();
  45. return isCallbackEnabled(Opts, CallbackName);
  46. }
  47. bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const {
  48. AnalyzerOptions &Opts = State->getStateManager().getOwningEngine()
  49. .getAnalysisManager().getAnalyzerOptions();
  50. return isCallbackEnabled(Opts, CallbackName);
  51. }
  52. public:
  53. void checkPreStmt(const CastExpr *CE, CheckerContext &C) const {
  54. if (isCallbackEnabled(C, "PreStmtCastExpr"))
  55. llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName()
  56. << ")\n";
  57. }
  58. void checkPostStmt(const CastExpr *CE, CheckerContext &C) const {
  59. if (isCallbackEnabled(C, "PostStmtCastExpr"))
  60. llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName()
  61. << ")\n";
  62. }
  63. void checkPreStmt(const ArraySubscriptExpr *SubExpr,
  64. CheckerContext &C) const {
  65. if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr"))
  66. llvm::errs() << "PreStmt<ArraySubscriptExpr>\n";
  67. }
  68. void checkPostStmt(const ArraySubscriptExpr *SubExpr,
  69. CheckerContext &C) const {
  70. if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr"))
  71. llvm::errs() << "PostStmt<ArraySubscriptExpr>\n";
  72. }
  73. void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const {
  74. if (isCallbackEnabled(C, "PreStmtCXXNewExpr"))
  75. llvm::errs() << "PreStmt<CXXNewExpr>\n";
  76. }
  77. void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const {
  78. if (isCallbackEnabled(C, "PostStmtCXXNewExpr"))
  79. llvm::errs() << "PostStmt<CXXNewExpr>\n";
  80. }
  81. void checkPreStmt(const CXXDeleteExpr *NE, CheckerContext &C) const {
  82. if (isCallbackEnabled(C, "PreStmtCXXDeleteExpr"))
  83. llvm::errs() << "PreStmt<CXXDeleteExpr>\n";
  84. }
  85. void checkPostStmt(const CXXDeleteExpr *NE, CheckerContext &C) const {
  86. if (isCallbackEnabled(C, "PostStmtCXXDeleteExpr"))
  87. llvm::errs() << "PostStmt<CXXDeleteExpr>\n";
  88. }
  89. void checkPreStmt(const CXXConstructExpr *NE, CheckerContext &C) const {
  90. if (isCallbackEnabled(C, "PreStmtCXXConstructExpr"))
  91. llvm::errs() << "PreStmt<CXXConstructExpr>\n";
  92. }
  93. void checkPostStmt(const CXXConstructExpr *NE, CheckerContext &C) const {
  94. if (isCallbackEnabled(C, "PostStmtCXXConstructExpr"))
  95. llvm::errs() << "PostStmt<CXXConstructExpr>\n";
  96. }
  97. void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
  98. if (isCallbackEnabled(C, "PreStmtOffsetOfExpr"))
  99. llvm::errs() << "PreStmt<OffsetOfExpr>\n";
  100. }
  101. void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const {
  102. if (isCallbackEnabled(C, "PostStmtOffsetOfExpr"))
  103. llvm::errs() << "PostStmt<OffsetOfExpr>\n";
  104. }
  105. bool evalCall(const CallEvent &Call, CheckerContext &C) const {
  106. if (isCallbackEnabled(C, "EvalCall")) {
  107. llvm::errs() << "EvalCall";
  108. if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
  109. llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
  110. llvm::errs() << " {argno: " << Call.getNumArgs() << '}';
  111. llvm::errs() << " [" << Call.getKindAsString() << ']';
  112. llvm::errs() << '\n';
  113. return true;
  114. }
  115. return false;
  116. }
  117. void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
  118. if (isCallbackEnabled(C, "PreCall")) {
  119. llvm::errs() << "PreCall";
  120. if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
  121. llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
  122. llvm::errs() << " [" << Call.getKindAsString() << ']';
  123. llvm::errs() << '\n';
  124. }
  125. }
  126. void checkPostCall(const CallEvent &Call, CheckerContext &C) const {
  127. if (isCallbackEnabled(C, "PostCall")) {
  128. llvm::errs() << "PostCall";
  129. if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl()))
  130. llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
  131. llvm::errs() << " [" << Call.getKindAsString() << ']';
  132. llvm::errs() << '\n';
  133. }
  134. }
  135. void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const {
  136. if (isCallbackEnabled(C, "EndFunction")) {
  137. llvm::errs() << "EndFunction\nReturnStmt: " << (S ? "yes" : "no") << "\n";
  138. if (!S)
  139. return;
  140. llvm::errs() << "CFGElement: ";
  141. CFGStmtMap *Map = C.getCurrentAnalysisDeclContext()->getCFGStmtMap();
  142. CFGElement LastElement = Map->getBlock(S)->back();
  143. if (LastElement.getAs<CFGStmt>())
  144. llvm::errs() << "CFGStmt\n";
  145. else if (LastElement.getAs<CFGAutomaticObjDtor>())
  146. llvm::errs() << "CFGAutomaticObjDtor\n";
  147. }
  148. }
  149. void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
  150. ExprEngine &Eng) const {
  151. if (isCallbackEnabled(BR.getAnalyzerOptions(), "EndAnalysis"))
  152. llvm::errs() << "EndAnalysis\n";
  153. }
  154. void checkNewAllocator(const CXXAllocatorCall &Call,
  155. CheckerContext &C) const {
  156. if (isCallbackEnabled(C, "NewAllocator"))
  157. llvm::errs() << "NewAllocator\n";
  158. }
  159. void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const {
  160. if (isCallbackEnabled(C, "Bind"))
  161. llvm::errs() << "Bind\n";
  162. }
  163. void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const {
  164. if (isCallbackEnabled(State, "LiveSymbols"))
  165. llvm::errs() << "LiveSymbols\n";
  166. }
  167. ProgramStateRef
  168. checkRegionChanges(ProgramStateRef State,
  169. const InvalidatedSymbols *Invalidated,
  170. ArrayRef<const MemRegion *> ExplicitRegions,
  171. ArrayRef<const MemRegion *> Regions,
  172. const LocationContext *LCtx, const CallEvent *Call) const {
  173. if (isCallbackEnabled(State, "RegionChanges"))
  174. llvm::errs() << "RegionChanges\n";
  175. return State;
  176. }
  177. ProgramStateRef checkPointerEscape(ProgramStateRef State,
  178. const InvalidatedSymbols &Escaped,
  179. const CallEvent *Call,
  180. PointerEscapeKind Kind) const {
  181. if (isCallbackEnabled(State, "PointerEscape"))
  182. llvm::errs() << "PointerEscape\n";
  183. return State;
  184. }
  185. };
  186. } // end anonymous namespace
  187. //===----------------------------------------------------------------------===//
  188. // Registration.
  189. //===----------------------------------------------------------------------===//
  190. void ento::registerAnalysisOrderChecker(CheckerManager &mgr) {
  191. mgr.registerChecker<AnalysisOrderChecker>();
  192. }
  193. bool ento::shouldRegisterAnalysisOrderChecker(const CheckerManager &mgr) {
  194. return true;
  195. }