From 8ebe48760cfdc78fbf4fc46413dde9470121b99e Mon Sep 17 00:00:00 2001 From: Roderich Schupp Date: Sun, 29 Sep 2013 18:12:03 +0200 Subject: [PATCH 5/5] test and fix for RT #52317: Calling run3 garbles STDIN --- lib/IPC/Run3.pm | 26 ++++++------------------- t/preserve_stdin.t | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 t/preserve_stdin.t diff --git a/lib/IPC/Run3.pm b/lib/IPC/Run3.pm index 12c9d8a..777e290 100644 --- a/lib/IPC/Run3.pm +++ b/lib/IPC/Run3.pm @@ -363,14 +363,12 @@ sub run3 { $options if defined $stderr; # this should make perl close these on exceptions -# local *STDIN_SAVE; + local *STDIN_SAVE; local *STDOUT_SAVE; local *STDERR_SAVE; - my $saved_fd0 = dup( 0 ) if defined $in_fh; - -# open STDIN_SAVE, "<&STDIN"# or croak "run3(): $! saving STDIN" -# if defined $in_fh; + open STDIN_SAVE, "<&STDIN" or croak "run3(): $! saving STDIN" + if defined $in_fh; open STDOUT_SAVE, ">&STDOUT" or croak "run3(): $! saving STDOUT" if defined $out_fh; open STDERR_SAVE, ">&STDERR" or croak "run3(): $! saving STDERR" @@ -378,17 +376,10 @@ sub run3 { my $errno; my $ok = eval { - # The open() call here seems to not force fd 0 in some cases; - # I ran in to trouble when using this in VCP, not sure why. - # the dup2() seems to work. - dup2( fileno $in_fh, 0 ) -# open STDIN, "<&=" . fileno $in_fh + open STDIN, "<&=" . fileno $in_fh or croak "run3(): $! redirecting STDIN" if defined $in_fh; -# close $in_fh or croak "$! closing STDIN temp file" -# if ref $stdin; - open STDOUT, ">&" . fileno $out_fh or croak "run3(): $! redirecting STDOUT" if defined $out_fh; @@ -428,13 +419,8 @@ sub run3 { my @errs; - if ( defined $saved_fd0 ) { - dup2( $saved_fd0, 0 ); - POSIX::close( $saved_fd0 ); - } - -# open STDIN, "<&STDIN_SAVE"# or push @errs, "run3(): $! restoring STDIN" -# if defined $in_fh; + open STDIN, "<&STDIN_SAVE" or push @errs, "run3(): $! restoring STDIN" + if defined $in_fh; open STDOUT, ">&STDOUT_SAVE" or push @errs, "run3(): $! restoring STDOUT" if defined $out_fh; open STDERR, ">&STDERR_SAVE" or push @errs, "run3(): $! restoring STDERR" diff --git a/t/preserve_stdin.t b/t/preserve_stdin.t new file mode 100644 index 0000000..8e090ee --- /dev/null +++ b/t/preserve_stdin.t @@ -0,0 +1,57 @@ +#!perl -w + +## test whether reading from STDIN is preserved when +## run3 is called in between reads + +use Test::More; +use IPC::Run3; +use File::Temp qw(tempfile); +use strict; + +# call run3 at different lines (problems might manifest itself +# on different lines, probably due to different buffering of input) +my @check_at = (5, 10, 50, 100, 200, 500); +plan tests => @check_at * 3; + +# create a test file for input containing 1000 lines +my $nlines = 1000; +my @exp_lines; +my ($fh, $file) = tempfile(UNLINK => 1); +for (my $i = 1; $i <= $nlines; $i++) +{ + my $line = "this is line $i"; + push @exp_lines, $line; + print $fh $line, "\n"; +} +close $fh; + + +my ( $in, $out, $err ); + +foreach my $n (@check_at) +{ + my $nread = 0; + my $unexpected; + open STDIN, "<", $file or die "can't open file $file: $!"; + while () + { + chomp; + $unexpected = qq[line $nread: expected "$exp_lines[$nread]", got "$_"\n] + unless $exp_lines[$nread] eq $_ || $unexpected; + $nread++; + + if ($nread == $n) + { + $in = "checking at line $n"; + run3 [ $^X, '-e', 'print uc $_ while <>' ], \$in, \$out, \$err; + die "command failed" unless $? == 0; + is($out, uc $in); + } + } + close STDIN; + + is($nread, $nlines, "STDIN was read completely"); + ok(!$unexpected, "STDIN as expected") or diag($unexpected); +} + + -- 1.8.5.3