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