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