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/AST/ExprCXX.h" 17 #include "clang/Analysis/CFGStmtMap.h" 18 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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< 31 check::PreStmt<CastExpr>, check::PostStmt<CastExpr>, 32 check::PreStmt<ArraySubscriptExpr>, 33 check::PostStmt<ArraySubscriptExpr>, check::PreStmt<CXXNewExpr>, 34 check::PostStmt<CXXNewExpr>, check::PreStmt<CXXDeleteExpr>, 35 check::PostStmt<CXXDeleteExpr>, check::PreStmt<CXXConstructExpr>, 36 check::PostStmt<CXXConstructExpr>, check::PreStmt<OffsetOfExpr>, 37 check::PostStmt<OffsetOfExpr>, check::PreCall, check::PostCall, 38 check::EndFunction, check::EndAnalysis, check::NewAllocator, 39 check::Bind, check::PointerEscape, check::RegionChanges, 40 check::LiveSymbols, eval::Call> { 41 42 bool isCallbackEnabled(const AnalyzerOptions &Opts, 43 StringRef CallbackName) const { 44 return Opts.getCheckerBooleanOption(this, "*") || 45 Opts.getCheckerBooleanOption(this, CallbackName); 46 } 47 48 bool isCallbackEnabled(CheckerContext &C, StringRef CallbackName) const { 49 AnalyzerOptions &Opts = C.getAnalysisManager().getAnalyzerOptions(); 50 return isCallbackEnabled(Opts, CallbackName); 51 } 52 53 bool isCallbackEnabled(ProgramStateRef State, StringRef CallbackName) const { 54 AnalyzerOptions &Opts = State->getStateManager().getOwningEngine() 55 .getAnalysisManager().getAnalyzerOptions(); 56 return isCallbackEnabled(Opts, CallbackName); 57 } 58 59 public: 60 void checkPreStmt(const CastExpr *CE, CheckerContext &C) const { 61 if (isCallbackEnabled(C, "PreStmtCastExpr")) 62 llvm::errs() << "PreStmt<CastExpr> (Kind : " << CE->getCastKindName() 63 << ")\n"; 64 } 65 66 void checkPostStmt(const CastExpr *CE, CheckerContext &C) const { 67 if (isCallbackEnabled(C, "PostStmtCastExpr")) 68 llvm::errs() << "PostStmt<CastExpr> (Kind : " << CE->getCastKindName() 69 << ")\n"; 70 } 71 72 void checkPreStmt(const ArraySubscriptExpr *SubExpr, 73 CheckerContext &C) const { 74 if (isCallbackEnabled(C, "PreStmtArraySubscriptExpr")) 75 llvm::errs() << "PreStmt<ArraySubscriptExpr>\n"; 76 } 77 78 void checkPostStmt(const ArraySubscriptExpr *SubExpr, 79 CheckerContext &C) const { 80 if (isCallbackEnabled(C, "PostStmtArraySubscriptExpr")) 81 llvm::errs() << "PostStmt<ArraySubscriptExpr>\n"; 82 } 83 84 void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const { 85 if (isCallbackEnabled(C, "PreStmtCXXNewExpr")) 86 llvm::errs() << "PreStmt<CXXNewExpr>\n"; 87 } 88 89 void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const { 90 if (isCallbackEnabled(C, "PostStmtCXXNewExpr")) 91 llvm::errs() << "PostStmt<CXXNewExpr>\n"; 92 } 93 94 void checkPreStmt(const CXXDeleteExpr *NE, CheckerContext &C) const { 95 if (isCallbackEnabled(C, "PreStmtCXXDeleteExpr")) 96 llvm::errs() << "PreStmt<CXXDeleteExpr>\n"; 97 } 98 99 void checkPostStmt(const CXXDeleteExpr *NE, CheckerContext &C) const { 100 if (isCallbackEnabled(C, "PostStmtCXXDeleteExpr")) 101 llvm::errs() << "PostStmt<CXXDeleteExpr>\n"; 102 } 103 104 void checkPreStmt(const CXXConstructExpr *NE, CheckerContext &C) const { 105 if (isCallbackEnabled(C, "PreStmtCXXConstructExpr")) 106 llvm::errs() << "PreStmt<CXXConstructExpr>\n"; 107 } 108 109 void checkPostStmt(const CXXConstructExpr *NE, CheckerContext &C) const { 110 if (isCallbackEnabled(C, "PostStmtCXXConstructExpr")) 111 llvm::errs() << "PostStmt<CXXConstructExpr>\n"; 112 } 113 114 void checkPreStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { 115 if (isCallbackEnabled(C, "PreStmtOffsetOfExpr")) 116 llvm::errs() << "PreStmt<OffsetOfExpr>\n"; 117 } 118 119 void checkPostStmt(const OffsetOfExpr *OOE, CheckerContext &C) const { 120 if (isCallbackEnabled(C, "PostStmtOffsetOfExpr")) 121 llvm::errs() << "PostStmt<OffsetOfExpr>\n"; 122 } 123 124 bool evalCall(const CallEvent &Call, CheckerContext &C) const { 125 if (isCallbackEnabled(C, "EvalCall")) { 126 llvm::errs() << "EvalCall"; 127 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) 128 llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; 129 llvm::errs() << " {argno: " << Call.getNumArgs() << '}'; 130 llvm::errs() << " [" << Call.getKindAsString() << ']'; 131 llvm::errs() << '\n'; 132 return true; 133 } 134 return false; 135 } 136 137 void checkPreCall(const CallEvent &Call, CheckerContext &C) const { 138 if (isCallbackEnabled(C, "PreCall")) { 139 llvm::errs() << "PreCall"; 140 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) 141 llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; 142 llvm::errs() << " [" << Call.getKindAsString() << ']'; 143 llvm::errs() << '\n'; 144 } 145 } 146 147 void checkPostCall(const CallEvent &Call, CheckerContext &C) const { 148 if (isCallbackEnabled(C, "PostCall")) { 149 llvm::errs() << "PostCall"; 150 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Call.getDecl())) 151 llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')'; 152 llvm::errs() << " [" << Call.getKindAsString() << ']'; 153 llvm::errs() << '\n'; 154 } 155 } 156 157 void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const { 158 if (isCallbackEnabled(C, "EndFunction")) { 159 llvm::errs() << "EndFunction\nReturnStmt: " << (S ? "yes" : "no") << "\n"; 160 if (!S) 161 return; 162 163 llvm::errs() << "CFGElement: "; 164 CFGStmtMap *Map = C.getCurrentAnalysisDeclContext()->getCFGStmtMap(); 165 CFGElement LastElement = Map->getBlock(S)->back(); 166 167 if (LastElement.getAs<CFGStmt>()) 168 llvm::errs() << "CFGStmt\n"; 169 else if (LastElement.getAs<CFGAutomaticObjDtor>()) 170 llvm::errs() << "CFGAutomaticObjDtor\n"; 171 } 172 } 173 174 void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, 175 ExprEngine &Eng) const { 176 if (isCallbackEnabled(BR.getAnalyzerOptions(), "EndAnalysis")) 177 llvm::errs() << "EndAnalysis\n"; 178 } 179 180 void checkNewAllocator(const CXXAllocatorCall &Call, 181 CheckerContext &C) const { 182 if (isCallbackEnabled(C, "NewAllocator")) 183 llvm::errs() << "NewAllocator\n"; 184 } 185 186 void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const { 187 if (isCallbackEnabled(C, "Bind")) 188 llvm::errs() << "Bind\n"; 189 } 190 191 void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const { 192 if (isCallbackEnabled(State, "LiveSymbols")) 193 llvm::errs() << "LiveSymbols\n"; 194 } 195 196 ProgramStateRef 197 checkRegionChanges(ProgramStateRef State, 198 const InvalidatedSymbols *Invalidated, 199 ArrayRef<const MemRegion *> ExplicitRegions, 200 ArrayRef<const MemRegion *> Regions, 201 const LocationContext *LCtx, const CallEvent *Call) const { 202 if (isCallbackEnabled(State, "RegionChanges")) 203 llvm::errs() << "RegionChanges\n"; 204 return State; 205 } 206 207 ProgramStateRef checkPointerEscape(ProgramStateRef State, 208 const InvalidatedSymbols &Escaped, 209 const CallEvent *Call, 210 PointerEscapeKind Kind) const { 211 if (isCallbackEnabled(State, "PointerEscape")) 212 llvm::errs() << "PointerEscape\n"; 213 return State; 214 } 215 }; 216 } // end anonymous namespace 217 218 //===----------------------------------------------------------------------===// 219 // Registration. 220 //===----------------------------------------------------------------------===// 221 222 void ento::registerAnalysisOrderChecker(CheckerManager &mgr) { 223 mgr.registerChecker<AnalysisOrderChecker>(); 224 } 225 226 bool ento::shouldRegisterAnalysisOrderChecker(const CheckerManager &mgr) { 227 return true; 228 } 229