1 1.1 joerg //==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg // This file reports various statistics about analyzer visitation. 9 1.1 joerg //===----------------------------------------------------------------------===// 10 1.1 joerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 11 1.1 joerg #include "clang/AST/DeclObjC.h" 12 1.1 joerg #include "clang/Basic/SourceManager.h" 13 1.1 joerg #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 14 1.1 joerg #include "clang/StaticAnalyzer/Core/Checker.h" 15 1.1 joerg #include "clang/StaticAnalyzer/Core/CheckerManager.h" 16 1.1 joerg #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 17 1.1 joerg #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 18 1.1 joerg #include "llvm/ADT/SmallPtrSet.h" 19 1.1 joerg #include "llvm/ADT/SmallString.h" 20 1.1 joerg #include "llvm/ADT/Statistic.h" 21 1.1 joerg #include "llvm/Support/raw_ostream.h" 22 1.1 joerg 23 1.1 joerg using namespace clang; 24 1.1 joerg using namespace ento; 25 1.1 joerg 26 1.1 joerg #define DEBUG_TYPE "StatsChecker" 27 1.1 joerg 28 1.1 joerg STATISTIC(NumBlocks, 29 1.1 joerg "The # of blocks in top level functions"); 30 1.1 joerg STATISTIC(NumBlocksUnreachable, 31 1.1 joerg "The # of unreachable blocks in analyzing top level functions"); 32 1.1 joerg 33 1.1 joerg namespace { 34 1.1 joerg class AnalyzerStatsChecker : public Checker<check::EndAnalysis> { 35 1.1 joerg public: 36 1.1 joerg void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const; 37 1.1 joerg }; 38 1.1 joerg } 39 1.1 joerg 40 1.1 joerg void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, 41 1.1 joerg BugReporter &B, 42 1.1 joerg ExprEngine &Eng) const { 43 1.1 joerg const CFG *C = nullptr; 44 1.1 joerg const SourceManager &SM = B.getSourceManager(); 45 1.1 joerg llvm::SmallPtrSet<const CFGBlock*, 32> reachable; 46 1.1 joerg 47 1.1 joerg // Root node should have the location context of the top most function. 48 1.1 joerg const ExplodedNode *GraphRoot = *G.roots_begin(); 49 1.1 joerg const LocationContext *LC = GraphRoot->getLocation().getLocationContext(); 50 1.1 joerg 51 1.1 joerg const Decl *D = LC->getDecl(); 52 1.1 joerg 53 1.1 joerg // Iterate over the exploded graph. 54 1.1 joerg for (ExplodedGraph::node_iterator I = G.nodes_begin(); 55 1.1 joerg I != G.nodes_end(); ++I) { 56 1.1 joerg const ProgramPoint &P = I->getLocation(); 57 1.1 joerg 58 1.1 joerg // Only check the coverage in the top level function (optimization). 59 1.1 joerg if (D != P.getLocationContext()->getDecl()) 60 1.1 joerg continue; 61 1.1 joerg 62 1.1 joerg if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { 63 1.1 joerg const CFGBlock *CB = BE->getBlock(); 64 1.1 joerg reachable.insert(CB); 65 1.1 joerg } 66 1.1 joerg } 67 1.1 joerg 68 1.1 joerg // Get the CFG and the Decl of this block. 69 1.1 joerg C = LC->getCFG(); 70 1.1 joerg 71 1.1 joerg unsigned total = 0, unreachable = 0; 72 1.1 joerg 73 1.1 joerg // Find CFGBlocks that were not covered by any node 74 1.1 joerg for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) { 75 1.1 joerg const CFGBlock *CB = *I; 76 1.1 joerg ++total; 77 1.1 joerg // Check if the block is unreachable 78 1.1 joerg if (!reachable.count(CB)) { 79 1.1 joerg ++unreachable; 80 1.1 joerg } 81 1.1 joerg } 82 1.1 joerg 83 1.1 joerg // We never 'reach' the entry block, so correct the unreachable count 84 1.1 joerg unreachable--; 85 1.1 joerg // There is no BlockEntrance corresponding to the exit block as well, so 86 1.1 joerg // assume it is reached as well. 87 1.1 joerg unreachable--; 88 1.1 joerg 89 1.1 joerg // Generate the warning string 90 1.1 joerg SmallString<128> buf; 91 1.1 joerg llvm::raw_svector_ostream output(buf); 92 1.1 joerg PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); 93 1.1 joerg if (!Loc.isValid()) 94 1.1 joerg return; 95 1.1 joerg 96 1.1 joerg if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { 97 1.1 joerg const NamedDecl *ND = cast<NamedDecl>(D); 98 1.1 joerg output << *ND; 99 1.1 joerg } 100 1.1 joerg else if (isa<BlockDecl>(D)) { 101 1.1 joerg output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn(); 102 1.1 joerg } 103 1.1 joerg 104 1.1 joerg NumBlocksUnreachable += unreachable; 105 1.1 joerg NumBlocks += total; 106 1.1.1.2 joerg std::string NameOfRootFunction = std::string(output.str()); 107 1.1 joerg 108 1.1 joerg output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: " 109 1.1 joerg << unreachable << " | Exhausted Block: " 110 1.1 joerg << (Eng.wasBlocksExhausted() ? "yes" : "no") 111 1.1 joerg << " | Empty WorkList: " 112 1.1 joerg << (Eng.hasEmptyWorkList() ? "yes" : "no"); 113 1.1 joerg 114 1.1 joerg B.EmitBasicReport(D, this, "Analyzer Statistics", "Internal Statistics", 115 1.1 joerg output.str(), PathDiagnosticLocation(D, SM)); 116 1.1 joerg 117 1.1 joerg // Emit warning for each block we bailed out on. 118 1.1 joerg typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator; 119 1.1 joerg const CoreEngine &CE = Eng.getCoreEngine(); 120 1.1 joerg for (ExhaustedIterator I = CE.blocks_exhausted_begin(), 121 1.1 joerg E = CE.blocks_exhausted_end(); I != E; ++I) { 122 1.1 joerg const BlockEdge &BE = I->first; 123 1.1 joerg const CFGBlock *Exit = BE.getDst(); 124 1.1 joerg if (Exit->empty()) 125 1.1 joerg continue; 126 1.1 joerg const CFGElement &CE = Exit->front(); 127 1.1 joerg if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) { 128 1.1 joerg SmallString<128> bufI; 129 1.1 joerg llvm::raw_svector_ostream outputI(bufI); 130 1.1 joerg outputI << "(" << NameOfRootFunction << ")" << 131 1.1 joerg ": The analyzer generated a sink at this point"; 132 1.1 joerg B.EmitBasicReport( 133 1.1 joerg D, this, "Sink Point", "Internal Statistics", outputI.str(), 134 1.1 joerg PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC)); 135 1.1 joerg } 136 1.1 joerg } 137 1.1 joerg } 138 1.1 joerg 139 1.1 joerg void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) { 140 1.1 joerg mgr.registerChecker<AnalyzerStatsChecker>(); 141 1.1 joerg } 142 1.1 joerg 143 1.1.1.2 joerg bool ento::shouldRegisterAnalyzerStatsChecker(const CheckerManager &mgr) { 144 1.1 joerg return true; 145 1.1 joerg } 146