Ping!

Attached are an updated patch for ccc-analyzer and a similar patch for scan-build, please review.

On 06.11.2014 20:27, Jordan Rose wrote:
I think my point was "why bother forking at all if we're using open to run a subprocess?".
Ah, got it! Attached is an updated patch.


Also, this will fail if the path contains spaces:
Corrected.


+ my $ExecLine = join(' ', $Clang, "-###", $mode, @$Args, "2>&1", "|");
+    open(PS, $ExecLine);

Do newer Perls on newer Windows support the list form of open?
No, at least ActivePerl, StrawberryPerl and Dwimperl.

Current perl docs state:
'open to ||-| and |-|| are unsupported. (Win32, RISC OS)' (http://perldoc.perl.org/perlport.html#open)
and
'The open(FOO, "|-") and open(BAR, "-|") constructs are not yet implemented.' (http://perldoc.perl.org/perlfork.html)

Jordan


On Nov 5, 2014, at 11:54 , Anton Yartsev <[email protected] <mailto:[email protected]>> wrote:

Ping!
It seems that fork is the only native perl mean for creating subprocesses. There is a number of packages that provide means for spawning at cpan.org <http://cpan.org>, but they are not guarantee to be included at the users perl distribution.
Looking at this code, it's weird that we're doing this as a fork/exec (or not-exec) at all. Why can't we just spawn a sub-process?

Jordan


On Oct 21, 2014, at 6:47 , Anton Yartsev <[email protected] <mailto:[email protected]>> wrote:

Hi all,

Attached is the patch that prevents ccc/c++-analyzer from hang if launched with ActivePerl or Strawberry Perl interpreters. The patch replaces the code that creates a pipe from child to parent to the more portable explicit writing to parent, this prevent interpreters from hang. The conditions for hang are: child should open a pipe to the parent and parent should read from the child, otherwise no hang.

The problem is possibly caused by the bug in emulation of 'fork' by Perl interpreters on Windows. From perlfork <http://perldoc.perl.org/perlfork.html> documentation, BUGS section: "In certain cases, the OS-level handles created by the pipe(), socket(), and accept() operators are apparently not duplicated accurately in pseudo-processes. This only happens in some situations, but where it does happen, it may result in deadlocks between the read and write ends of pipe handles, or inability to send or receive data across socket handles."

An example from perlfork documentation also hangs:

# simulate open(FOO, "-|")
sub pipe_from_fork ($) {
    my $parent = shift;
    pipe $parent, my $child or die;
    my $pid = fork();
    die "fork() failed: $!" unless defined $pid;
    if ($pid) {
      close $child;
    }
    else {
      close $parent;
      open(STDOUT, ">&=" . fileno($child)) or die;
    }
  $pid;
}

if (pipe_from_fork('BAR')) {
# parent
while (<BAR>) { print; }
  close BAR;
}
else {
  # child
  print "pipe_from_fork\n";
  exit(0);
}

The hang is not reproduced only with the MSYS Perl.

OK to commit?
--
Anton
<ccc-analyzer_fork_open_hang.patch>



--
Anton


--
Anton



--
Anton


--
Anton

Index: ccc-analyzer
===================================================================
--- ccc-analyzer	(revision 222850)
+++ ccc-analyzer	(working copy)
@@ -150,28 +150,18 @@
   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 $ClangLine;
+  my $ExecLine = join(' ', "$Clang", "-###", $mode, @$Args, "2>&1", "|");
+  open(PS, $ExecLine);
+  while ( <PS> ) {
     next if (!/\s"?-cc1"?\s/);
-    $line = $_;
+    $ClangLine = $_;
   }
 
-  waitpid($pid,0);
-  close(FROM_CHILD);
-
-  die "could not find clang line\n" if (!defined $line);
+  die "could not find clang line\n" if (!defined $ClangLine);
   # Strip leading and trailing whitespace characters.
-  $line =~ s/^\s+|\s+$//g;
-  my @items = quotewords('\s+', 0, $line);
+  $ClangLine =~ s/^\s+|\s+$//g;
+  my @items = quotewords('\s+', 0, $ClangLine);
   my $cmd = shift @items;
   die "cannot find 'clang' in 'clang' command\n" if (!($cmd =~ /clang/));
   return \@items;
@@ -251,26 +241,14 @@
   # Capture the STDOUT of clang and reroute it 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 $ExecLine = join(' ', "$Cmd", @CmdArgs, "2>&1", "|");
+  open(PS, $ExecLine);
+  while ( <PS> ) {
     print $ofh $_;
     print STDERR $_;
   }
   close $ofh;
-
-  waitpid($pid,0);
-  close(FROM_CHILD);
   my $Result = $?;
 
   # Did the command die because of a signal?
Index: scan-build
===================================================================
--- scan-build	(revision 222851)
+++ scan-build	(working copy)
@@ -1232,16 +1232,9 @@
   }
   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(' ', "$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 @@
         }
       }
     }
-    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(' ', "$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 @@
     else {
       print("\nAVAILABLE CHECKERS:\n\n");
       my $skip = 0;
-      while(<FROM_CHILD>) {
+       while(<PS>) {
         if (/experimental/) {
           $skip = 1;
           next;
@@ -1314,10 +1298,8 @@
         }
         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);
   }
 
 print <<ENDTEXT
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to