04bfb0
From 35608a1658fe75c79ca53d96aea6cf7cb2a98615 Mon Sep 17 00:00:00 2001
04bfb0
From: Tony Cook <tony@develop-help.com>
04bfb0
Date: Thu, 9 May 2019 09:52:30 +1000
04bfb0
Subject: [PATCH] (perl #122112) a simpler fix for pclose() aborted by a signal
04bfb0
MIME-Version: 1.0
04bfb0
Content-Type: text/plain; charset=UTF-8
04bfb0
Content-Transfer-Encoding: 8bit
04bfb0
04bfb0
This change results in a zombie child process for the lifetime of
04bfb0
the process, but I think that's the responsibility of the signal
04bfb0
handler that aborted pclose().
04bfb0
04bfb0
We could add some magic to retry (and retry and retry) waiting on
04bfb0
child process as we rewind (since there's no other way to remove
04bfb0
the zombie), but the program has chosen implicitly to abort the
04bfb0
wait() done by pclose() and it's best to honor that.
04bfb0
04bfb0
If we do choose to retry the wait() we might be blocking an attempt
04bfb0
by the process to terminate, whether by exit() or die().
04bfb0
04bfb0
If a program does need more flexible handling there's always
04bfb0
pipe()/fork()/exec() and/or the various event-driven frameworks on
04bfb0
CPAN.
04bfb0
04bfb0
Signed-off-by: Petr Písař <ppisar@redhat.com>
04bfb0
---
04bfb0
 doio.c      | 12 +++++++++++-
04bfb0
 t/io/pipe.t |  2 --
04bfb0
 2 files changed, 11 insertions(+), 3 deletions(-)
04bfb0
04bfb0
diff --git a/doio.c b/doio.c
04bfb0
index 0cc4e55404..05a06968dc 100644
04bfb0
--- a/doio.c
04bfb0
+++ b/doio.c
04bfb0
@@ -1779,7 +1779,17 @@ Perl_io_close(pTHX_ IO *io, GV *gv, bool not_implicit, bool warn_on_fail)
04bfb0
 
04bfb0
     if (IoIFP(io)) {
04bfb0
 	if (IoTYPE(io) == IoTYPE_PIPE) {
04bfb0
-	    const int status = PerlProc_pclose(IoIFP(io));
04bfb0
+            PerlIO *fh = IoIFP(io);
04bfb0
+            int status;
04bfb0
+
04bfb0
+            /* my_pclose() can propagate signals which might bypass any code
04bfb0
+               after the call here if the signal handler throws an exception.
04bfb0
+               This would leave the handle in the IO object and try to close it again
04bfb0
+               when the SV is destroyed on unwind or global destruction.
04bfb0
+               So NULL it early.
04bfb0
+            */
04bfb0
+            IoOFP(io) = IoIFP(io) = NULL;
04bfb0
+	    status = PerlProc_pclose(fh);
04bfb0
 	    if (not_implicit) {
04bfb0
 		STATUS_NATIVE_CHILD_SET(status);
04bfb0
 		retval = (STATUS_UNIX == 0);
04bfb0
diff --git a/t/io/pipe.t b/t/io/pipe.t
04bfb0
index 1d01db6af6..fc3071300d 100644
04bfb0
--- a/t/io/pipe.t
04bfb0
+++ b/t/io/pipe.t
04bfb0
@@ -255,9 +255,7 @@ close \$fh;
04bfb0
 PROG
04bfb0
     print $prog;
04bfb0
     my $out = fresh_perl($prog, {});
04bfb0
-    $::TODO = "not fixed yet";
04bfb0
     cmp_ok($out, '!~', qr/refcnt/, "no exception from PerlIO");
04bfb0
-    undef $::TODO;
04bfb0
     # checks that that program did something rather than failing to
04bfb0
     # compile
04bfb0
     cmp_ok($out, '=~', qr/Died at/, "but we did get the exception from die");
04bfb0
-- 
04bfb0
2.20.1
04bfb0