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