brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · 309e3d2 Raw
231 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This checker prints callbacks that are called during analysis.10// This is required to ensure that callbacks are fired in order11// 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 24using namespace clang;25using namespace ento;26 27namespace {28 29class AnalysisOrderChecker30    : 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 59public: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      // We can't return `true` from this callback without binding the return133      // value. Let's just fallthrough here and return `false`.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, bool AtDeclInit,188                 CheckerContext &C) const {189    if (isCallbackEnabled(C, "Bind"))190      llvm::errs() << "Bind\n";191  }192 193  void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SymReaper) const {194    if (isCallbackEnabled(State, "LiveSymbols"))195      llvm::errs() << "LiveSymbols\n";196  }197 198  ProgramStateRef199  checkRegionChanges(ProgramStateRef State,200                     const InvalidatedSymbols *Invalidated,201                     ArrayRef<const MemRegion *> ExplicitRegions,202                     ArrayRef<const MemRegion *> Regions,203                     const LocationContext *LCtx, const CallEvent *Call) const {204    if (isCallbackEnabled(State, "RegionChanges"))205      llvm::errs() << "RegionChanges\n";206    return State;207  }208 209  ProgramStateRef checkPointerEscape(ProgramStateRef State,210                                     const InvalidatedSymbols &Escaped,211                                     const CallEvent *Call,212                                     PointerEscapeKind Kind) const {213    if (isCallbackEnabled(State, "PointerEscape"))214      llvm::errs() << "PointerEscape\n";215    return State;216  }217};218} // end anonymous namespace219 220//===----------------------------------------------------------------------===//221// Registration.222//===----------------------------------------------------------------------===//223 224void ento::registerAnalysisOrderChecker(CheckerManager &mgr) {225  mgr.registerChecker<AnalysisOrderChecker>();226}227 228bool ento::shouldRegisterAnalysisOrderChecker(const CheckerManager &mgr) {229  return true;230}231