Updated scan-build:

- Idempotent operations are on by default, to match --analyze in the driver.
- Integrated stats calculation based on parsing warnings emitted with the -analyzer-stats flag. The new -stats flag enables this.
- New -maxloop flag to pass down a maxloop value to the analyzer.

llvm-svn: 115123
This commit is contained in:
Tom Care 2010-09-30 01:12:05 +00:00
parent c768287968
commit ea7c48ccf7
1 changed files with 134 additions and 12 deletions

View File

@ -120,7 +120,8 @@ my %AnalysesDefaultEnabled = (
# Do not enable the missing -dealloc check by default.
# '-analyzer-check-objc-missing-dealloc' => 1,
'-analyzer-check-objc-unused-ivars' => 1,
'-analyzer-check-security-syntactic' => 1
'-analyzer-check-security-syntactic' => 1,
'-analyzer-check-idempotent-operations' => 1
);
##----------------------------------------------------------------------------##
@ -303,6 +304,38 @@ sub UpdateInFilePath {
system("mv", "$fname.tmp", $fname);
}
##----------------------------------------------------------------------------##
# AddStatLine - Decode and insert a statistics line into the database.
##----------------------------------------------------------------------------##
sub AddStatLine {
my $Line = shift;
my $Stats = shift;
print $Line . "\n";
my $Regex = qr/(.*?)\ :\ (.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
\ CFGBlocks:\ (\d+)\ \|\ Aborted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
\ (yes|no)/x;
if ($Line !~ $Regex) {
return;
}
# Create a hash of the interesting fields
my $Row = {
Filename => $1,
Function => $2,
Total => $3,
Unreachable => $4,
Aborted => $5,
Empty => $6
};
# Add them to the stats array
push @$Stats, $Row;
}
##----------------------------------------------------------------------------##
# ScanFile - Scan a report file for various identifying attributes.
##----------------------------------------------------------------------------##
@ -317,6 +350,7 @@ sub ScanFile {
my $Index = shift;
my $Dir = shift;
my $FName = shift;
my $Stats = shift;
# Compute a digest for the report file. Determine if we have already
# scanned a file that looks just like it.
@ -337,11 +371,12 @@ sub ScanFile {
# Scan the report file for tags.
open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
my $BugType = "";
my $BugFile = "";
my $BugCategory;
my $BugPathLength = 1;
my $BugLine = 0;
my $BugType = "";
my $BugFile = "";
my $BugCategory = "";
my $BugDescription = "";
my $BugPathLength = 1;
my $BugLine = 0;
while (<IN>) {
last if (/<!-- BUGMETAEND -->/);
@ -362,6 +397,9 @@ sub ScanFile {
elsif (/<!-- BUGCATEGORY (.*) -->$/) {
$BugCategory = $1;
}
elsif (/<!-- BUGDESC (.*) -->$/) {
$BugDescription = $1;
}
}
close(IN);
@ -369,7 +407,13 @@ sub ScanFile {
if (!defined $BugCategory) {
$BugCategory = "Other";
}
# Don't add internal statistics to the bug reports
if ($BugCategory =~ /statistics/i) {
AddStatLine($BugDescription, $Stats);
return;
}
push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugLine,
$BugPathLength ];
}
@ -403,14 +447,62 @@ sub CopyFiles {
if (! -r $CSS);
}
##----------------------------------------------------------------------------##
# CalcStats - Calculates visitation statistics and returns the string.
##----------------------------------------------------------------------------##
sub CalcStats {
my $Stats = shift;
my $TotalBlocks = 0;
my $UnreachedBlocks = 0;
my $TotalFunctions = scalar(@$Stats);
my $BlockAborted = 0;
my $WorkListAborted = 0;
my $Aborted = 0;
# Calculate the unique files
my $FilesHash = {};
foreach my $Row (@$Stats) {
$FilesHash->{$Row->{Filename}} = 1;
$TotalBlocks += $Row->{Total};
$UnreachedBlocks += $Row->{Unreachable};
$BlockAborted++ if $Row->{Aborted} eq 'yes';
$WorkListAborted++ if $Row->{Empty} eq 'no';
$Aborted++ if $Row->{Aborted} eq 'yes' || $Row->{Empty} eq 'no';
}
my $TotalFiles = scalar(keys(%$FilesHash));
# Calculations
my $PercentAborted = sprintf("%.2f", $Aborted / $TotalFunctions * 100);
my $PercentBlockAborted = sprintf("%.2f", $BlockAborted / $TotalFunctions
* 100);
my $PercentWorkListAborted = sprintf("%.2f", $WorkListAborted /
$TotalFunctions * 100);
my $PercentBlocksUnreached = sprintf("%.2f", $UnreachedBlocks / $TotalBlocks
* 100);
my $StatsString = "Analyzed $TotalBlocks blocks in $TotalFunctions functions"
. " in $TotalFiles files\n"
. "$Aborted functions aborted early ($PercentAborted%)\n"
. "$BlockAborted had aborted blocks ($PercentBlockAborted%)\n"
. "$WorkListAborted had unfinished worklists ($PercentWorkListAborted%)\n"
. "$UnreachedBlocks blocks were never reached ($PercentBlocksUnreached%)\n";
return $StatsString;
}
##----------------------------------------------------------------------------##
# Postprocess - Postprocess the results of an analysis scan.
##----------------------------------------------------------------------------##
sub Postprocess {
my $Dir = shift;
my $BaseDir = shift;
my $Dir = shift;
my $BaseDir = shift;
my $AnalyzerStats = shift;
die "No directory specified." if (!defined $Dir);
@ -430,8 +522,9 @@ sub Postprocess {
}
# Scan each report file and build an index.
my @Index;
foreach my $file (@files) { ScanFile(\@Index, $Dir, $file); }
my @Index;
my @Stats;
foreach my $file (@files) { ScanFile(\@Index, $Dir, $file, \@Stats); }
# Scan the failures directory and use the information in the .info files
# to update the common prefix directory.
@ -745,6 +838,9 @@ ENDTEXT
system("chmod", "755", $Dir);
if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
# Print statistics
print CalcStats(\@Stats) if $AnalyzerStats;
my $Num = scalar(@Index);
Diag("$Num bugs found.\n");
if ($Num > 0 && -r "$Dir/index.html") {
@ -930,6 +1026,12 @@ ADVANCED OPTIONS:
-no-failure-reports - Do not create a 'failures' subdirectory that includes
analyzer crash reports and preprocessed source files.
-stats - Generates visitation statistics for the project being analyzed.
-maxloop N - specifiy the number of times a block can be visited before giving
up. Default is 3. Increase for more comprehensive coverage at a
cost of speed.
AVAILABLE ANALYSES (multiple analyses may be specified):
ENDTEXT
@ -1004,6 +1106,8 @@ my @AnalysesToRun;
my $StoreModel;
my $ConstraintsModel;
my $OutputFormat = "html";
my $AnalyzerStats = 0;
my $MaxLoop = 0;
if (!@ARGV) {
DisplayHelp();
@ -1156,6 +1260,16 @@ while (@ARGV) {
$ENV{"CCC_REPORT_FAILURES"} = 0;
next;
}
if ($arg eq "-stats") {
shift @ARGV;
$AnalyzerStats = 1;
next;
}
if ($arg eq "-maxloop") {
shift @ARGV;
$MaxLoop = shift @ARGV;
next;
}
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
@ -1220,6 +1334,14 @@ if ($AnalyzeHeaders) {
push @AnalysesToRun,"-analyzer-opt-analyze-headers";
}
if ($AnalyzerStats) {
push @AnalysesToRun, '-analyzer-stats';
}
if ($MaxLoop > 0) {
push @AnalysesToRun, '-analyzer-max-loop ' . $MaxLoop;
}
$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
if (defined $StoreModel) {
@ -1244,7 +1366,7 @@ if (defined $OutputFormat) {
}
elsif ($OutputFormat =~ /html/) {
# Postprocess the HTML directory.
my $NumBugs = Postprocess($HtmlDir, $BaseDir);
my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats);
if ($ViewResults and -r "$HtmlDir/index.html") {
Diag "Analysis run complete.\n";