r241201 - [analyzer] Prevent ccc/c++-analyzer from hanging on Windows.

Anton Yartsev anton.yartsev at gmail.com
Wed Jul 1 15:35:30 PDT 2015


Author: ayartsev
Date: Wed Jul  1 17:35:29 2015
New Revision: 241201

URL: http://llvm.org/viewvc/llvm-project?rev=241201&view=rev
Log:
[analyzer] Prevent ccc/c++-analyzer from hanging on Windows.

'fork'+'exec' combination made scan-build and ccc-analyzer hang under Windows. The patch replaces 'fork'+'exec' with more reliable 'system' (ccc-analyzer) and piped 'open' (scan-build). See http://reviews.llvm.org/D8774 and http://reviews.llvm.org/D9357 for more details.

Modified:
    cfe/trunk/tools/scan-build/ccc-analyzer
    cfe/trunk/tools/scan-build/scan-build

Modified: cfe/trunk/tools/scan-build/ccc-analyzer
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/scan-build/ccc-analyzer?rev=241201&r1=241200&r2=241201&view=diff
==============================================================================
--- cfe/trunk/tools/scan-build/ccc-analyzer (original)
+++ cfe/trunk/tools/scan-build/ccc-analyzer Wed Jul  1 17:35:29 2015
@@ -22,6 +22,33 @@ use File::Basename;
 use Text::ParseWords;
 
 ##===----------------------------------------------------------------------===##
+# List form 'system' with STDOUT and STDERR captured.
+##===----------------------------------------------------------------------===##
+
+sub silent_system {
+  my $HtmlDir = shift;
+  my $Command = shift;
+
+  # Save STDOUT and STDERR and redirect to a temporary file.
+  open OLDOUT, ">&", \*STDOUT;
+  open OLDERR, ">&", \*STDERR;
+  my ($TmpFH, $TmpFile) = tempfile("temp_buf_XXXXXX",
+                                   DIR => $HtmlDir,
+                                   UNLINK => 1);
+  open(STDOUT, ">$TmpFile");
+  open(STDERR, ">&", \*STDOUT);
+
+  # Invoke 'system', STDOUT and STDERR are output to a temporary file.
+  system $Command, @_;
+
+  # Restore STDOUT and STDERR.
+  open STDOUT, ">&", \*OLDOUT;
+  open STDERR, ">&", \*OLDERR;
+
+  return $TmpFH;
+}
+
+##===----------------------------------------------------------------------===##
 # Compiler command setup.
 ##===----------------------------------------------------------------------===##
 
@@ -145,7 +172,7 @@ sub ProcessClangFailure {
   print OUT "@$Args\n";
   close OUT;
   `uname -a >> $PPFile.info.txt 2>&1`;
-  `$Compiler -v >> $PPFile.info.txt 2>&1`;
+  `"$Compiler" -v >> $PPFile.info.txt 2>&1`;
   rename($ofile, "$PPFile.stderr.txt");
   return (basename $PPFile);
 }
@@ -155,27 +182,15 @@ sub ProcessClangFailure {
 ##----------------------------------------------------------------------------##
 
 sub GetCCArgs {
+  my $HtmlDir = shift;
   my $mode = shift;
   my $Args = shift;
-
-  pipe (FROM_CHILD, TO_PARENT);
-  my $pid = fork();
-  if ($pid == 0) {
-    close FROM_CHILD;
-    open(STDOUT,">&", \*TO_PARENT);
-    open(STDERR,">&", \*TO_PARENT);
-    exec $Clang, "-###", $mode, @$Args;
-  }
-  close(TO_PARENT);
   my $line;
-  while (<FROM_CHILD>) {
+  my $OutputStream = silent_system($HtmlDir, $Clang, "-###", $mode, @$Args);
+  while (<$OutputStream>) {
     next if (!/\s"?-cc1"?\s/);
     $line = $_;
   }
-
-  waitpid($pid,0);
-  close(FROM_CHILD);
-
   die "could not find clang line\n" if (!defined $line);
   # Strip leading and trailing whitespace characters.
   $line =~ s/^\s+|\s+$//g;
@@ -207,7 +222,7 @@ sub Analyze {
     $Cmd = $Clang;
 
     # Create arguments for doing regular parsing.
-    my $SyntaxArgs = GetCCArgs("-fsyntax-only", \@Args);
+    my $SyntaxArgs = GetCCArgs($HtmlDir, "-fsyntax-only", \@Args);
     @CmdArgsSansAnalyses = @$SyntaxArgs;
 
     # Create arguments for doing static analysis.
@@ -230,7 +245,7 @@ sub Analyze {
       push @Args, "-Xclang", "-analyzer-viz-egraph-ubigraph";
     }
 
-    my $AnalysisArgs = GetCCArgs("--analyze", \@Args);
+    my $AnalysisArgs = GetCCArgs($HtmlDir, "--analyze", \@Args);
     @CmdArgs = @$AnalysisArgs;
   }
 
@@ -255,31 +270,19 @@ sub Analyze {
     print STDERR "#SHELL (cd '$dir' && @PrintArgs)\n";
   }
 
-  # Capture the STDERR of clang and send it to a temporary file.
-  # Capture the STDOUT of clang and reroute it to ccc-analyzer's STDERR.
+  # Save STDOUT and STDERR of clang to a temporary file and reroute
+  # all clang output to ccc-analyzer's STDERR.
   # We save the output file in the 'crashes' directory if clang encounters
   # any problems with the file.
-  pipe (FROM_CHILD, TO_PARENT);
-  my $pid = fork();
-  if ($pid == 0) {
-    close FROM_CHILD;
-    open(STDOUT,">&", \*TO_PARENT);
-    open(STDERR,">&", \*TO_PARENT);
-    exec $Cmd, @CmdArgs;
-  }
-
-  close TO_PARENT;
   my ($ofh, $ofile) = tempfile("clang_output_XXXXXX", DIR => $HtmlDir);
-
-  while (<FROM_CHILD>) {
+  
+  my $OutputStream = silent_system($HtmlDir, $Cmd, @CmdArgs);
+  while ( <$OutputStream> ) {
     print $ofh $_;
     print STDERR $_;
   }
-  close $ofh;
-
-  waitpid($pid,0);
-  close(FROM_CHILD);
   my $Result = $?;
+  close $ofh;
 
   # Did the command die because of a signal?
   if ($ReportFailures) {

Modified: cfe/trunk/tools/scan-build/scan-build
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/scan-build/scan-build?rev=241201&r1=241200&r2=241201&view=diff
==============================================================================
--- cfe/trunk/tools/scan-build/scan-build (original)
+++ cfe/trunk/tools/scan-build/scan-build Wed Jul  1 17:35:29 2015
@@ -1232,16 +1232,9 @@ ENDTEXT
   }
   my %EnabledCheckers;
   foreach my $lang ("c", "objective-c", "objective-c++", "c++") {
-    pipe(FROM_CHILD, TO_PARENT);
-    my $pid = fork();
-    if ($pid == 0) {
-      close FROM_CHILD;
-      open(STDOUT,">&", \*TO_PARENT);
-      open(STDERR,">&", \*TO_PARENT);
-      exec $Clang, ( @PluginLoadCommandline_xclang, '--analyze', '-x', $lang, '-', '-###');
-    }
-    close(TO_PARENT);
-    while(<FROM_CHILD>) {
+    my $ExecLine = join(' ', qq/"$Clang"/, @PluginLoadCommandline_xclang, "--analyze", "-x", $lang, "-", "-###", "2>&1", "|");
+    open(PS, $ExecLine);
+    while (<PS>) {
       foreach my $val (split /\s+/) {
         $val =~ s/\"//g;
         if ($val =~ /-analyzer-checker\=([^\s]+)/) {
@@ -1249,23 +1242,14 @@ ENDTEXT
         }
       }
     }
-    waitpid($pid,0);
-    close(FROM_CHILD);
   }
 
   # Query clang for complete list of checkers.
   if (defined $Clang && -x $Clang) {
-    pipe(FROM_CHILD, TO_PARENT);
-    my $pid = fork();
-    if ($pid == 0) {
-      close FROM_CHILD;
-      open(STDOUT,">&", \*TO_PARENT);
-      open(STDERR,">&", \*TO_PARENT);
-      exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
-    }
-    close(TO_PARENT);
+    my $ExecLine = join(' ', qq/"$Clang"/, "-cc1", @PluginsToLoad, "-analyzer-checker-help", "2>&1", "|");
+    open(PS, $ExecLine);
     my $foundCheckers = 0;
-    while(<FROM_CHILD>) {
+    while (<PS>) {
       if (/CHECKERS:/) {
         $foundCheckers = 1;
         last;
@@ -1277,7 +1261,7 @@ ENDTEXT
     else {
       print("\nAVAILABLE CHECKERS:\n\n");
       my $skip = 0;
-      while(<FROM_CHILD>) {
+       while(<PS>) {
         if (/experimental/) {
           $skip = 1;
           next;
@@ -1314,10 +1298,9 @@ ENDTEXT
         }
         print $_;
       }
-      print "\nNOTE: \"+\" indicates that an analysis is enabled by default.\n"
+      print "\nNOTE: \"+\" indicates that an analysis is enabled by default.\n";
     }
-    waitpid($pid,0);
-    close(FROM_CHILD);
+    close PS;
   }
 
 print <<ENDTEXT





More information about the cfe-commits mailing list