mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 13:50:11 +00:00
Added AnalyzerStatsChecker, a path sensitive check that reports visitation statistics about analysis. Running clang with the -analyzer-stats flag will emit warnings containing the information. We can then run a postanalysis script to take this data and give useful information about how much the analyzer missed in a project.
llvm-svn: 113568
This commit is contained in:
parent
712bd0a604
commit
4545b2df42
@ -264,6 +264,7 @@ public:
|
||||
|
||||
// Functions for external checking of whether we have unfinished work
|
||||
bool wasBlockAborted() const { return CoreEngine.wasBlockAborted(); }
|
||||
bool hasEmptyWorkList() const { return !CoreEngine.getWorkList()->hasWork(); }
|
||||
bool hasWorkRemaining() const {
|
||||
return wasBlockAborted() || CoreEngine.getWorkList()->hasWork();
|
||||
}
|
||||
|
@ -64,6 +64,8 @@ def analysis_WarnSizeofPointer : Flag<"-warn-sizeof-pointer">,
|
||||
HelpText<"Warn about unintended use of sizeof() on pointer expressions">;
|
||||
def analysis_WarnIdempotentOps : Flag<"-analyzer-check-idempotent-operations">,
|
||||
HelpText<"Warn about idempotent operations">;
|
||||
def analysis_AnalyzerStats : Flag<"-analyzer-stats">,
|
||||
HelpText<"Emit warnings with analyzer statistics">;
|
||||
|
||||
def analyzer_store : Separate<"-analyzer-store">,
|
||||
HelpText<"Source Code Analysis - Abstract Memory Store Models">;
|
||||
|
@ -65,6 +65,7 @@ public:
|
||||
unsigned AnalyzeAll : 1;
|
||||
unsigned AnalyzerDisplayProgress : 1;
|
||||
unsigned AnalyzeNestedBlocks : 1;
|
||||
unsigned AnalyzerStats : 1;
|
||||
unsigned EagerlyAssume : 1;
|
||||
unsigned IdempotentOps : 1;
|
||||
unsigned PurgeDead : 1;
|
||||
@ -73,7 +74,6 @@ public:
|
||||
unsigned VisualizeEGUbi : 1;
|
||||
unsigned EnableExperimentalChecks : 1;
|
||||
unsigned EnableExperimentalInternalChecks : 1;
|
||||
unsigned EnableIdempotentOperationChecker : 1;
|
||||
unsigned InlineCall : 1;
|
||||
unsigned UnoptimizedCFG : 1;
|
||||
|
||||
@ -85,6 +85,7 @@ public:
|
||||
AnalyzeAll = 0;
|
||||
AnalyzerDisplayProgress = 0;
|
||||
AnalyzeNestedBlocks = 0;
|
||||
AnalyzerStats = 0;
|
||||
EagerlyAssume = 0;
|
||||
PurgeDead = 1;
|
||||
TrimGraph = 0;
|
||||
|
@ -350,6 +350,10 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
|
||||
|| C.Opts.EnableExperimentalInternalChecks)
|
||||
RegisterIdempotentOperationChecker(Eng);
|
||||
|
||||
// Enable AnalyzerStatsChecker if it was given as an argument
|
||||
if (C.Opts.AnalyzerStats)
|
||||
RegisterAnalyzerStatsChecker(Eng);
|
||||
|
||||
// Set the graph auditor.
|
||||
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
|
||||
if (mgr.shouldVisualizeUbigraph()) {
|
||||
|
104
clang/lib/Checker/AnalyzerStatsChecker.cpp
Normal file
104
clang/lib/Checker/AnalyzerStatsChecker.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
//==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This file reports various statistics about analyzer visitation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Checker/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/Checker/PathSensitive/ExplodedGraph.h"
|
||||
#include "clang/Checker/BugReporter/BugReporter.h"
|
||||
#include "GRExprEngineExperimentalChecks.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
class AnalyzerStatsChecker : public CheckerVisitor<AnalyzerStatsChecker> {
|
||||
public:
|
||||
static void *getTag();
|
||||
void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, GRExprEngine &Eng);
|
||||
|
||||
private:
|
||||
llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
|
||||
};
|
||||
}
|
||||
|
||||
void *AnalyzerStatsChecker::getTag() {
|
||||
static int x = 0;
|
||||
return &x;
|
||||
}
|
||||
|
||||
void clang::RegisterAnalyzerStatsChecker(GRExprEngine &Eng) {
|
||||
Eng.registerCheck(new AnalyzerStatsChecker());
|
||||
}
|
||||
|
||||
void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G,
|
||||
BugReporter &B,
|
||||
GRExprEngine &Eng) {
|
||||
const CFG *C = 0;
|
||||
const Decl *D = 0;
|
||||
const LocationContext *LC = 0;
|
||||
const SourceManager &SM = B.getSourceManager();
|
||||
|
||||
// Iterate over explodedgraph
|
||||
for (ExplodedGraph::node_iterator I = G.nodes_begin();
|
||||
I != G.nodes_end(); ++I) {
|
||||
const ProgramPoint &P = I->getLocation();
|
||||
// Save the LocationContext if we don't have it already
|
||||
if (!LC)
|
||||
LC = P.getLocationContext();
|
||||
|
||||
if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
|
||||
const CFGBlock *CB = BE->getDst();
|
||||
reachable.insert(CB);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the CFG and the Decl of this block
|
||||
C = LC->getCFG();
|
||||
D = LC->getAnalysisContext()->getDecl();
|
||||
|
||||
unsigned total = 0, unreachable = 0;
|
||||
|
||||
// Find CFGBlocks that were not covered by any node
|
||||
for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
|
||||
const CFGBlock *CB = *I;
|
||||
++total;
|
||||
// Check if the block is unreachable
|
||||
if (!reachable.count(CB)) {
|
||||
++unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
// We never 'reach' the entry block, so correct the unreachable count
|
||||
unreachable--;
|
||||
|
||||
// Generate the warning string
|
||||
llvm::SmallString<128> buf;
|
||||
llvm::raw_svector_ostream output(buf);
|
||||
PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
|
||||
output << Loc.getFilename() << " : ";
|
||||
|
||||
if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
|
||||
const NamedDecl *ND = cast<NamedDecl>(D);
|
||||
output << ND;
|
||||
}
|
||||
else if (isa<BlockDecl>(D)) {
|
||||
output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
|
||||
}
|
||||
|
||||
output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
|
||||
<< unreachable << " | Aborted Block: "
|
||||
<< (Eng.wasBlockAborted() ? "no" : "yes")
|
||||
<< " | Empty WorkList: "
|
||||
<< (Eng.hasEmptyWorkList() ? "yes" : "no") << "\n";
|
||||
|
||||
B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
|
||||
D->getLocation());
|
||||
}
|
@ -7,6 +7,7 @@ add_clang_library(clangChecker
|
||||
AggExprVisitor.cpp
|
||||
AnalysisConsumer.cpp
|
||||
AnalysisManager.cpp
|
||||
AnalyzerStatsChecker.cpp
|
||||
ArrayBoundChecker.cpp
|
||||
AttrNonNullChecker.cpp
|
||||
BasicConstraintManager.cpp
|
||||
|
@ -19,6 +19,7 @@ namespace clang {
|
||||
|
||||
class GRExprEngine;
|
||||
|
||||
void RegisterAnalyzerStatsChecker(GRExprEngine &Eng);
|
||||
void RegisterCStringChecker(GRExprEngine &Eng);
|
||||
void RegisterIdempotentOperationChecker(GRExprEngine &Eng);
|
||||
void RegisterMallocChecker(GRExprEngine &Eng);
|
||||
|
@ -99,6 +99,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
|
||||
Res.push_back("-analyzer-display-progress");
|
||||
if (Opts.AnalyzeNestedBlocks)
|
||||
Res.push_back("-analyzer-opt-analyze-nested-blocks");
|
||||
if (Opts.AnalyzerStats)
|
||||
Res.push_back("-analyzer-stats");
|
||||
if (Opts.EagerlyAssume)
|
||||
Res.push_back("-analyzer-eagerly-assume");
|
||||
if (!Opts.PurgeDead)
|
||||
@ -815,6 +817,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
|
||||
Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
|
||||
Opts.AnalyzeNestedBlocks =
|
||||
Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
|
||||
Opts.AnalyzerStats = Args.hasArg(OPT_analysis_AnalyzerStats);
|
||||
Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead);
|
||||
Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
|
||||
Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
|
||||
|
14
clang/test/Analysis/analyzer-stats.c
Normal file
14
clang/test/Analysis/analyzer-stats.c
Normal file
@ -0,0 +1,14 @@
|
||||
// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-check-dead-stores -verify -Wno-unreachable-code -analyzer-opt-analyze-nested-blocks -analyzer-stats %s
|
||||
|
||||
int foo();
|
||||
|
||||
int test() { // expected-warning{{Total CFGBlocks}}
|
||||
int a = 1;
|
||||
a = 34 / 12;
|
||||
|
||||
if (foo())
|
||||
return a;
|
||||
|
||||
a /= 4;
|
||||
return a;
|
||||
}
|
Loading…
Reference in New Issue
Block a user