use strict;
use warnings;
use Cwd;
+use File::Temp qw/ tempfile /;
+use File::Path qw / mkpath /;
+
+##----------------------------------------------------------------------------##
+# Process Clang Crashes.
+##----------------------------------------------------------------------------##
+
+sub GetPPExt {
+ my $Lang = shift;
+ if ($Lang =~ /objective-c/) { return ".mi"; }
+ return ".i";
+}
+
+sub ProcessClangCrash {
+ my ($Clang, $Lang, $file, $Args, $HtmlDir) = @_;
+ my $Dir = "$HtmlDir/crashes";
+ mkpath $Dir;
+ my ($PPH, $PPFile) = tempfile("clang_crash_XXXXXX",
+ SUFFIX => GetPPExt($Lang),
+ DIR => $Dir);
+
+ system $Clang, @$Args, "-E", "-o", $PPFile;
+ close ($PPH);
+ open (OUT, ">", "$PPFile.info") or die "Cannot open $PPFile.info\n";
+ print OUT "$file";
+ close OUT;
+}
##----------------------------------------------------------------------------##
# Running the analyzer.
my $RunAnalyzer = 0;
my $Cmd;
my @CmdArgs;
+ my @CmdArgsSansAnalyses;
if ($Lang =~ /header/) {
exit 0 if (!defined ($Output));
# Remove the PCH extension.
$Output =~ s/[.]gch$//;
push @CmdArgs,$Output;
+ @CmdArgsSansAnalyses = @CmdArgs;
}
else {
$Cmd = $Clang;
- push @CmdArgs,(split /\s/,$Analyses);
push @CmdArgs,'-DIBOutlet=__attribute__((iboutlet))';
push @CmdArgs,@$Args;
+ @CmdArgsSansAnalyses = @CmdArgs;
+ push @CmdArgs,(split /\s/,$Analyses);
$RunAnalyzer = 1;
}
push @CmdArgs,'-o';
push @CmdArgs,$HtmlDir;
}
-
- system $Cmd,@CmdArgs;
+
+ system $Cmd,@CmdArgs;
+
+ # Did the command die because of a signal?
+ if ($? & 127 and $Cmd eq $Clang and defined $HtmlDir) {
+ ProcessClangCrash($Clang, $Lang, $file, \@CmdArgsSansAnalyses, $HtmlDir);
+ }
}
##----------------------------------------------------------------------------##
use strict;
use warnings;
-use File::Temp qw/ :mktemp /;
use FindBin qw($RealBin);
use Digest::MD5;
use File::Basename;
}
}
+sub DiagCrashes {
+ my $Dir = shift;
+ Diag ("The analyzer crashed on some source files.\n");
+ Diag ("Preprocessed versions of crashed files were depositied in '$Dir/crashes'.\n");
+ Diag ("Please consider submitting a bug report using these files:\n");
+ Diag (" http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\n")
+}
+
sub DieDiag {
if ($UseColor) {
print BOLD, RED "$Prog: ";
if (/Available Source Code Analyses/) {
$FoundAnalysis = 1;
}
-
+
next;
}
}
opendir(DIR, $Dir);
- my @files = grep(/^report-.*\.html$/,readdir(DIR));
+ my $Crashes = 0;
+ my @files = grep { if ($_ eq "crashes") { $Crashes++; }
+ /^report-.*\.html$/; } readdir(DIR);
closedir(DIR);
- if (scalar(@files) == 0) {
+ if (scalar(@files) == 0 and $Crashes == 0) {
Diag("Removing directory '$Dir' because it contains no reports.\n");
system ("rm", "-fR", $Dir);
-
# Remove the base directory if it contains no files (don't use '-R').
- if (defined $BaseDir) { system ("rm", "-f", $BaseDir); }
-
- Diag("No bugs found.\n");
+ system ("rm", "-f", $BaseDir) if (defined $BaseDir);
return 0;
}
- # Scan each report file and build an index.
-
- my @Index;
-
+ # Scan each report file and build an index.
+ my @Index;
foreach my $file (@files) { ScanFile(\@Index, $Dir, $file); }
# Generate an index.html file.
body { color:#000000; background-color:#ffffff }
body { font-family: Helvetica, sans-serif; font-size:9pt }
h1 { font-size:12pt }
- table.sortable thead {
+ table thead {
background-color:#eee; color:#666666;
font-weight: bold; cursor: default;
text-align:center;
border-bottom: 2px solid #000000;
font-weight: bold; font-family: Verdana
}
- table.sortable { border: 1px #000000 solid }
- table.sortable { border-collapse: collapse; border-spacing: 0px }
+ table { border: 1px #000000 solid }
+ table { border-collapse: collapse; border-spacing: 0px }
td { border-bottom: 1px #000000 dotted }
td { padding:5px; padding-left:8px; padding-right:8px }
td { text-align:left; font-size:9pt }
<body>
ENDTEXT
- # Print out the summary table.
-
- my %Totals;
+ if (scalar(@files)) {
+ # Print out the summary table.
+ my %Totals;
- for my $row ( @Index ) {
+ for my $row ( @Index ) {
+ #my $bug_type = lc($row->[1]);
+ my $bug_type = ($row->[1]);
- #my $bug_type = lc($row->[1]);
- my $bug_type = ($row->[1]);
-
- if (!defined $Totals{$bug_type}) {
- $Totals{$bug_type} = 1;
+ if (!defined $Totals{$bug_type}) { $Totals{$bug_type} = 1; }
+ else { $Totals{$bug_type}++; }
}
- else {
- $Totals{$bug_type}++;
+
+ print OUT "<h3>Bug Summary</h3>";
+
+ if (defined $BuildName) {
+ print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
}
- }
-
- print OUT "<h3>Summary</h3>";
-
- if (defined $BuildName) {
- print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
- }
print OUT <<ENDTEXT;
<table class="sortable">
</tr>
ENDTEXT
- for my $key ( sort { $a cmp $b } keys %Totals ) {
- my $x = lc($key);
- $x =~ s/[ ,'"]+/_/g;
- print OUT "<tr><td>$key</td><td>$Totals{$key}</td><td><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></td></tr>\n";
- }
+ for my $key ( sort { $a cmp $b } keys %Totals ) {
+ my $x = lc($key);
+ $x =~ s/[ ,'"]+/_/g;
+ print OUT "<tr><td>$key</td><td>$Totals{$key}</td><td><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></td></tr>\n";
+ }
# Print out the table of errors.
</tr>
ENDTEXT
- my $prefix = GetPrefix();
- my $regex;
- my $InFileRegex;
- my $InFilePrefix = "File:</td><td>";
+ my $prefix = GetPrefix();
+ my $regex;
+ my $InFileRegex;
+ my $InFilePrefix = "File:</td><td>";
- if (defined $prefix) {
- $regex = qr/^\Q$prefix\E/is;
- $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
- }
+ if (defined $prefix) {
+ $regex = qr/^\Q$prefix\E/is;
+ $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
+ }
- for my $row ( sort { $a->[1] cmp $b->[1] } @Index ) {
+ for my $row ( sort { $a->[1] cmp $b->[1] } @Index ) {
- my $x = lc($row->[1]);
- $x =~ s/[ ,'"]+/_/g;
+ my $x = lc($row->[1]);
+ $x =~ s/[ ,'"]+/_/g;
- print OUT "<tr class=\"bt_$x\">\n";
+ print OUT "<tr class=\"bt_$x\">\n";
- my $ReportFile = $row->[0];
+ my $ReportFile = $row->[0];
- print OUT " <td class=\"DESC\">";
- #print OUT lc($row->[1]);
- print OUT $row->[1];
- print OUT "</td>\n";
+ print OUT " <td class=\"DESC\">";
+ #print OUT lc($row->[1]);
+ print OUT $row->[1];
+ print OUT "</td>\n";
- # Update the file prefix.
+ # Update the file prefix.
- my $fname = $row->[2];
- if (defined $regex) {
- $fname =~ s/$regex//;
- UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
- }
+ my $fname = $row->[2];
+ if (defined $regex) {
+ $fname =~ s/$regex//;
+ UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
+ }
- print OUT "<td>$fname</td>\n";
+ print OUT "<td>$fname</td>\n";
- # Print the rest of the columns.
- for my $j ( 3 .. $#{$row} ) {
- print OUT "<td>$row->[$j]</td>\n"
- }
+ # Print the rest of the columns.
+ for my $j ( 3 .. $#{$row} ) {
+ print OUT "<td>$row->[$j]</td>\n"
+ }
- # Emit the "View" link.
- print OUT " <td class=\"View\"><a href=\"$ReportFile#EndPath\">View</a></td>\n";
+ # Emit the "View" link.
+ print OUT " <td class=\"View\"><a href=\"$ReportFile#EndPath\">View</a></td>\n";
- # End the row.
- print OUT "</tr>\n";
+ # End the row.
+ print OUT "</tr>\n";
+ }
+
+ print OUT "</table>\n";
}
+
+ if ($Crashes) {
+ # Read the crash directory for files.
+ opendir(DIR, "$Dir/crashes");
+ my @files = grep { /[.]info$/ } readdir(DIR);
+ closedir(DIR);
+
+ if (scalar(@files)) {
+ print OUT <<ENDTEXT;
+<h3>Analyzer Crashes</h3>
+
+<p>The analyzer crashed while processing the following files:</p>
+
+<table>
+<thead><tr><td>Source File</td><td>Preprocessed File</td></tr></thead>
+ENDTEXT
- print OUT "</table>\n</body></html>\n";
- close(OUT);
+ foreach my $file (sort @files) {
+ $file =~ /(.+).info$/;
+ # Get the preprocessed file.
+ my $ppfile = $1;
+ # Open the info file and get the name of the source file.
+ open (INFO, "$Dir/crashes/$file") or
+ die "Cannot open $Dir/crashes/$file\n";
+ my $srcfile = <INFO>;
+ close (INFO);
+ # Print the information in the table.
+ print OUT "<tr><td>$srcfile</td><td class=\"View\"><a href=\"crashes/$ppfile\">View</a></td></tr>\n";
+ }
+ print OUT <<ENDTEXT;
+</table>
+<p>Please consider submitting preprocessed files as <a href="http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs">bug reports</a>.</p>
+ENDTEXT
+ }
+ }
+
+ print OUT "</body></html>\n";
+ close(OUT);
CopyJS($Dir);
# Make sure $Dir and $BaseDir are world readable/executable.
Diag("Open '$Dir/index.html' to examine bug reports.\n");
}
+ DiagCrashes($Dir) if ($Crashes);
+
return $Num;
}