|
|
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 |
|