Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IO::Pipe relies on STDIN and STDOUT #7872

Open
p5pRT opened this issue Apr 12, 2005 · 9 comments
Open

IO::Pipe relies on STDIN and STDOUT #7872

p5pRT opened this issue Apr 12, 2005 · 9 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 12, 2005

Migrated from rt.perl.org#34931 (status was 'open')

Searchable as RT34931$

@p5pRT
Copy link
Author

p5pRT commented Apr 12, 2005

From zefram@fysh.org

Created by zefram@fysh.org

The ->writer and ->reader methods on IO​::Pipe rely on STDIN and STDOUT
(respectively) being attached to the usual file descriptors. If they
are not, then the child process ends up with its end of the pipe attached
to the wrong file descriptor. Example​:

$ echo foo | perl -MIO​::Pipe -we '*STDIN = *STDERR; $p = IO​::Pipe->new->writer("cat"); $p->printflush("bar\n"); sleep 1'
foo
$

I ran into this problem in an Apache mod_perl handler, which runs in
an environment where STDIN->fileno == 1. (STDOUT->fileno == 1 also.)
I've no idea why Apache does that, and I'm not sure I want to find out,
Apache being the mess that it is. Anyway, this bizarre STDIN wasn't a
problem, because it wasn't being used anywhere, until I started using
IO​::Pipe. I found a workaround​:

  local *STDIN = IO​::Handle->new_from_fd(0, "r");

Presumably IO​::Pipe could do something akin to this internally, to ensure
that the child is always plumbed in correctly.

Perl Info

Flags:
    category=library
    severity=medium

Site configuration information for perl v5.8.4:

Configured by Debian Project at Sun Dec 12 09:48:10 EST 2004.

Summary of my perl5 (revision 5 version 8 subversion 4) configuration:
  Platform:
    osname=linux, osvers=2.4.27-ti1211, archname=i386-linux-thread-multi
    uname='linux kosh 2.4.27-ti1211 #1 sun sep 19 18:17:45 est 2004 i686 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=i386-linux -Dprefix=/usr -Dprivlib=/usr/share/perl/5.8 -Darchlib=/usr/lib/perl/5.8 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.8.4 -Dsitearch=/usr/local/lib/perl/5.8.4 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Uusesfio -Uusenm -Duseshrplib -Dlibperl=libperl.so.5.8.4 -Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -I/usr/local/include'
    ccversion='', gccversion='3.3.5 (Debian 1:3.3.5-3)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.3.2.so, so=so, useshrplib=true, libperl=libperl.so.5.8.4
    gnulibc_version='2.3.2'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.8.4:
    /etc/perl
    /usr/local/lib/perl/5.8.4
    /usr/local/share/perl/5.8.4
    /usr/lib/perl5
    /usr/share/perl5
    /usr/lib/perl/5.8
    /usr/share/perl/5.8
    /usr/local/lib/site_perl
    /usr/local/lib/perl/5.8.3
    /usr/local/share/perl/5.8.3
    /usr/local/lib/perl/5.8.2
    /usr/local/share/perl/5.8.2
    .


Environment for perl v5.8.4:
    HOME=/root
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/usr/sbin:/sbin:/usr/local/sbin:/usr/local/armourplate/bin:/usr/bin:/bin:/usr/local/bin
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Apr 13, 2005

From schubiger@cpan.org

On 12 Apr, Zefram wrote​:

: The ->writer and ->reader methods on IO​::Pipe rely on STDIN and STDOUT
: (respectively) being attached to the usual file descriptors. If they
: are not, then the child process ends up with its end of the pipe attached
: to the wrong file descriptor. Example​:
:
: $ echo foo | perl -MIO​::Pipe -we '*STDIN = *STDERR; $p =
: IO​::Pipe->new->writer("cat"); $p->printflush("bar\n"); sleep 1'
: foo
: $
:
: I ran into this problem in an Apache mod_perl handler, which runs in
: an environment where STDIN->fileno == 1. (STDOUT->fileno == 1 also.)
: I've no idea why Apache does that, and I'm not sure I want to find out,
: Apache being the mess that it is. Anyway, this bizarre STDIN wasn't a
: problem, because it wasn't being used anywhere, until I started using
: IO​::Pipe. I found a workaround​:
:
: local *STDIN = IO​::Handle->new_from_fd(0, "r");
:
: Presumably IO​::Pipe could do something akin to this internally, to ensure
: that the child is always plumbed in correctly.

Inline Patch
--- lib/IO/Pipe.pm	Sun Apr  4 15:32:35 2004
+++ lib/IO/Pipe.pm	Wed Apr 13 05:38:32 2005
@@ -51,6 +51,8 @@
     }
     elsif(defined $pid) { # Child or spawn
         my $fh;
+	local *STDIN  = IO::Handle->new_from_fd(0, 'r') unless fileno(STDIN)  == 0;
+	local *STDOUT = IO::Handle->new_from_fd(1, 'w') unless fileno(STDOUT) == 1;
         my $io = $rw ? \*STDIN : \*STDOUT;
         my ($mode, $save) = $rw ? "r" : "w";
         if ($do_spawn) {

@p5pRT
Copy link
Author

p5pRT commented Apr 13, 2005

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Apr 13, 2005

From nick@ing-simmons.net

Steven P Schubiger <steven@​accognoscere.org> writes​:

On 12 Apr, Zefram wrote​:

​: The ->writer and ->reader methods on IO​::Pipe rely on STDIN and STDOUT
​: (respectively) being attached to the usual file descriptors. If they
​: are not, then the child process ends up with its end of the pipe attached
​: to the wrong file descriptor. Example​:
​:
​: $ echo foo | perl -MIO​::Pipe -we '*STDIN = *STDERR; $p =
​: IO​::Pipe->new->writer("cat"); $p->printflush("bar\n"); sleep 1'
​: foo
​: $
​:
​: I ran into this problem in an Apache mod_perl handler, which runs in
​: an environment where STDIN->fileno == 1. (STDOUT->fileno == 1 also.)
​: I've no idea why Apache does that, and I'm not sure I want to find out,
​: Apache being the mess that it is. Anyway, this bizarre STDIN wasn't a
​: problem, because it wasn't being used anywhere, until I started using
​: IO​::Pipe. I found a workaround​:
​:
​: local *STDIN = IO​::Handle->new_from_fd(0, "r");
​:
​: Presumably IO​::Pipe could do something akin to this internally, to ensure
​: that the child is always plumbed in correctly.

--- lib/IO/Pipe.pm Sun Apr 4 15​:32​:35 2004
+++ lib/IO/Pipe.pm Wed Apr 13 05​:38​:32 2005
@​@​ -51,6 +51,8 @​@​
}
elsif(defined $pid) { # Child or spawn
my $fh;
+ local *STDIN = IO​::Handle->new_from_fd(0, 'r') unless fileno(STDIN) == 0;
+ local *STDOUT = IO​::Handle->new_from_fd(1, 'w') unless fileno(STDOUT) == 1;

I assume that has been tested. It looks worryingly like the

  my $foo = "something" if (...);

problem...

    my $io = $rw ? \\\*STDIN : \\\*STDOUT;
    my \($mode\, $save\) = $rw ? "r" : "w";
    if \($do\_spawn\) \{

@p5pRT
Copy link
Author

p5pRT commented Apr 13, 2005

From perl5-porters@ton.iguana.be

In article <200504130242.j3D2_viU019110@​accognoscere.homeunix.org>,
  Steven P Schubiger <steven@​accognoscere.org> writes​:

--- lib/IO/Pipe.pm Sun Apr 4 15​:32​:35 2004
+++ lib/IO/Pipe.pm Wed Apr 13 05​:38​:32 2005
@​@​ -51,6 +51,8 @​@​
}
elsif(defined $pid) { # Child or spawn
my $fh;
+ local *STDIN = IO​::Handle->new_from_fd(0, 'r') unless fileno(STDIN) == 0;
+ local *STDOUT = IO​::Handle->new_from_fd(1, 'w') unless fileno(STDOUT) == 1;
my $io = $rw ? \*STDIN : \*STDOUT;
my ($mode, $save) = $rw ? "r" : "w";
if ($do_spawn) {

Isn't that getting a bit silly ? The code isn't interested in STDIN and
STDOUT at all anymore, it just wants to fdopen fd 0 or fd 1
(irrespective of where perl STDIN and STDOUT go).
Why not directly do that fdopen without all the dancing ?

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2005

From @ysth

On Wed, Apr 13, 2005 at 10​:10​:10PM +0100, Nick Ing-Simmons wrote​:

+ local *STDIN = IO​::Handle->new_from_fd(0, 'r') unless fileno(STDIN) == 0;
+ local *STDOUT = IO​::Handle->new_from_fd(1, 'w') unless fileno(STDOUT) == 1;

I assume that has been tested. It looks worryingly like the

    my $foo = "something" if \(\.\.\.\);

problem...

That's not a problem with local.

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2005

From schubiger@cpan.org

On 13 Apr, Nick Ing-Simmons wrote​:

: I assume that has been tested.

Yes and it does, what it's supposed to do.

Steven

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2005

From schubiger@cpan.org

On 13 Apr, Ton Hospel wrote​:

: Isn't that getting a bit silly ? The code isn't interested in STDIN and
: STDOUT at all anymore, it just wants to fdopen fd 0 or fd 1
: (irrespective of where perl STDIN and STDOUT go).
: Why not directly do that fdopen without all the dancing ?

I disagree. Are you aware that the handle gets blessed into
an "IO​::Handle" object at line 71? Substituting the creation of the
handles with a simple fdopen doesn't seem to suffice, unless we apply
some changes, that exceed the minor range.

Steven

@p5pRT
Copy link
Author

p5pRT commented Apr 14, 2005

From perl5-porters@ton.iguana.be

In article <200504141028.j3EAStRF006350@​accognoscere.homeunix.org>,
  Steven P Schubiger <steven@​accognoscere.org> writes​:

On 13 Apr, Ton Hospel wrote​:

​: Isn't that getting a bit silly ? The code isn't interested in STDIN and
​: STDOUT at all anymore, it just wants to fdopen fd 0 or fd 1
​: (irrespective of where perl STDIN and STDOUT go).
​: Why not directly do that fdopen without all the dancing ?

I disagree. Are you aware that the handle gets blessed into
an "IO​::Handle" object at line 71? Substituting the creation of the
handles with a simple fdopen doesn't seem to suffice, unless we apply
some changes, that exceed the minor range.

Steven

In that previous mail I was thinking in terms of something like​:

$io = IO​::Handle->new;
$io->fdopen(0, "r");

but that seems to dup in the wrong direction.
I suppose what's really needed is simply a dup2 from e.g. $me->reader to
0. The exact blessings of all handles are moot after the exec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants