summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2011-06-05 15:58:39 +0200
committerNicholas Clark <nick@ccl4.org>2011-06-11 08:48:14 +0200
commit031f91ce84f46612589c760c55adb30af25b87b5 (patch)
tree6a2b1a6e6e8a58f34eca8efc49a45704aa5f8468 /ext
parentf598f6deabaea2ddb1fe1242577961f817614c8b (diff)
downloadperl-031f91ce84f46612589c760c55adb30af25b87b5.tar.gz
IPC::Open3::open3() shouldn't fail if any of *STD{IN,OUT,ERR} are localized.
Previously it would fail on Win32, because spawn_with_handles() would attempt to duplicate all three, ignoring failures at this point, but then report failure to close any as a fatal error, even if this was because the earlier dup-ing had failed. Also avoid a warning in the *nix code path in open3() if STDERR is localized (and hence fileno STDERR is undefined).
Diffstat (limited to 'ext')
-rw-r--r--ext/IPC-Open3/lib/IPC/Open3.pm12
-rw-r--r--ext/IPC-Open3/t/IPC-Open3.t25
2 files changed, 32 insertions, 5 deletions
diff --git a/ext/IPC-Open3/lib/IPC/Open3.pm b/ext/IPC-Open3/lib/IPC/Open3.pm
index 4513fffc3a..4396603144 100644
--- a/ext/IPC-Open3/lib/IPC/Open3.pm
+++ b/ext/IPC-Open3/lib/IPC/Open3.pm
@@ -283,7 +283,8 @@ sub _open3 {
xopen \*STDERR, ">&=" . fileno $kid_err;
}
} else {
- xopen \*STDERR, ">&STDOUT" if fileno(STDERR) != fileno(STDOUT);
+ xopen \*STDERR, ">&STDOUT"
+ if defined fileno(STDERR) && fileno(STDERR) != fileno(STDOUT);
}
return 0 if ($cmd[0] eq '-');
exec @cmd or do {
@@ -388,7 +389,7 @@ sub spawn_with_handles {
foreach $fd (@$fds) {
$fd->{tmp_copy} = IO::Handle->new_from_fd($fd->{handle}, $fd->{mode});
- $saved{fileno $fd->{handle}} = $fd->{tmp_copy};
+ $saved{fileno $fd->{handle}} = $fd->{tmp_copy} if $fd->{tmp_copy};
}
foreach $fd (@$fds) {
bless $fd->{handle}, 'IO::Handle'
@@ -431,9 +432,12 @@ sub spawn_with_handles {
push @errs, "IO::Pipe: Can't spawn-NOWAIT: $!" if !$pid || $pid < 0;
}
- foreach $fd (@$fds) {
+ # Do this in reverse, so that STDERR is restored first:
+ foreach $fd (reverse @$fds) {
$fd->{handle}->fdopen($fd->{tmp_copy}, $fd->{mode});
- $fd->{tmp_copy}->close or croak "Can't close: $!";
+ }
+ foreach (values %saved) {
+ $_->close or croak "Can't close: $!";
}
croak join "\n", @errs if @errs;
return $pid;
diff --git a/ext/IPC-Open3/t/IPC-Open3.t b/ext/IPC-Open3/t/IPC-Open3.t
index 79dd9367c0..0ecb841b13 100644
--- a/ext/IPC-Open3/t/IPC-Open3.t
+++ b/ext/IPC-Open3/t/IPC-Open3.t
@@ -14,7 +14,7 @@ BEGIN {
}
use strict;
-use Test::More tests => 25;
+use Test::More tests => 37;
use IO::Handle;
use IPC::Open3;
@@ -159,3 +159,26 @@ $TB->current_test($test);
$pid = eval { open3 'WRITE', '', 'ERROR', '/non/existent/program'; };
like($@, qr/^open3: Modification of a read-only value attempted at /,
'open3 faults read-only parameters correctly') or do {waitpid $pid, 0};
+
+foreach my $handle (qw (DUMMY STDIN STDOUT STDERR)) {
+ local $::{$handle};
+ my $out = IO::Handle->new();
+ my $pid = eval {
+ local $SIG{__WARN__} = sub {
+ open my $fh, '>/dev/tty';
+ return if "@_" =~ m!^Use of uninitialized value \$fd.*IO/Handle\.pm!;
+ print $fh "@_";
+ die @_
+ };
+ open3 undef, $out, undef, $perl, '-le', "print q _# ${handle}_"
+ };
+ is($@, '', "No errors with localised $handle");
+ cmp_ok($pid, '>', 0, "Got a pid with localised $handle");
+ if ($handle eq 'STDOUT') {
+ is(<$out>, undef, "Expected no output with localised $handle");
+ } else {
+ like(<$out>, qr/\A# $handle\r?\n\z/,
+ "Expected output with localised $handle");
+ }
+ waitpid $pid, 0;
+}