Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.96k stars 555 forks source link

PerlIO refuses to read STDOUT or write STDIN #15434

Open p5pRT opened 8 years ago

p5pRT commented 8 years ago

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

Searchable as RT128591$

p5pRT commented 8 years ago

From @arc

Perl refuses to even try to read from STDOUT or write to STDIN\, even if the underlying file descriptors are readable and/or writable as appropriate.

I originally observed this using a dup'ed STDOUT​: a forked process wrote data to stdout\, and I wanted to be able to re-read that data after the child exited​:

  open STDOUT\, "+>"\, $file or die;   system 'generate_output';   seek STDOUT\, 0\, 0 or die;   \// die;

The readline emits a "Filehandle STDOUT opened only for output" warning\, and yields undef.

My first thought was that dup'ing filehandles should copy the PERLIO_F_CANREAD and PERLIO_F_CANWRITE flags from the original handle to the new one. But that actually isn't sufficient​: it's possible for Perl to be started with a readable stdout and/or a writable stdin​:

  $ perl -we '\ // die' 1\<> /dev/null   Filehandle STDOUT opened only for output at -e line 1.   Died at -e line 1.   $ perl -we 'STDIN->print("\n") // die' 0\<> /dev/null   Filehandle STDIN opened only for input at /Users/aaron/perl5/perlbrew/perls/perl-5.24.0/lib/5.24.0/darwin-2level/IO/Handle.pm line 420.   Died at -e line 1

Running those commands under "strace -e trace=read\,write" demonstrates that Perl makes no attempt to read from fd 1 or write to fd 0.

Perhaps the simplest fix would be to stop checking those flags before reading from or writing to a filehandle; we can expect the OS to yield EBADF iff the requested action is actually impossible.

Alternatively\, the flags should be set correctly on any handle that's either dup'ed\, or opened using the moral equivalent of fdopen (including the standard filehandles). That presumably involves using fcntl(F_GETFL) on the underlying descriptors in those cases.

-- Aaron Crane ** http​://aaroncrane.co.uk/

p5pRT commented 8 years ago

From @dcollinsn

Fixing this would probably resolve a few older bugs involving closing stdin/out/err and opening a new file as fd 0/1/2. On Jul 10\, 2016 10​:07\, "Aaron Crane" \perlbug\-followup@&#8203;perl\.org wrote​:

# New Ticket Created by Aaron Crane # Please include the string​: [perl #128591] # in the subject line of all future correspondence about this issue. # \<URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=128591 >

Perl refuses to even try to read from STDOUT or write to STDIN\, even if the underlying file descriptors are readable and/or writable as appropriate.

I originally observed this using a dup'ed STDOUT​: a forked process wrote data to stdout\, and I wanted to be able to re-read that data after the child exited​:

open STDOUT\, "\+>"\, $file or die;
system 'generate\_output';
seek STDOUT\, 0\, 0 or die;
\<STDOUT>// die;

The readline emits a "Filehandle STDOUT opened only for output" warning\, and yields undef.

My first thought was that dup'ing filehandles should copy the PERLIO_F_CANREAD and PERLIO_F_CANWRITE flags from the original handle to the new one. But that actually isn't sufficient​: it's possible for Perl to be started with a readable stdout and/or a writable stdin​:

$ perl \-we '\<STDOUT> // die' 1\<> /dev/null
Filehandle STDOUT opened only for output at \-e line 1\.
Died at \-e line 1\.
$ perl \-we 'STDIN\->print\("\\n"\) // die' 0\<> /dev/null
Filehandle STDIN opened only for input at

/Users/aaron/perl5/perlbrew/perls/perl-5.24.0/lib/5.24.0/darwin-2level/IO/Handle.pm line 420. Died at -e line 1

Running those commands under "strace -e trace=read\,write" demonstrates that Perl makes no attempt to read from fd 1 or write to fd 0.

Perhaps the simplest fix would be to stop checking those flags before reading from or writing to a filehandle; we can expect the OS to yield EBADF iff the requested action is actually impossible.

Alternatively\, the flags should be set correctly on any handle that's either dup'ed\, or opened using the moral equivalent of fdopen (including the standard filehandles). That presumably involves using fcntl(F_GETFL) on the underlying descriptors in those cases.

-- Aaron Crane ** http​://aaroncrane.co.uk/

p5pRT commented 8 years ago

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

p5pRT commented 8 years ago

From @exodist

Is this at all connected to https://rt-archive.perl.org/perl5/Ticket/Display.html?id=128530

On Jul 10\, 2016 10​:15 AM\, "Dan Collins" \dcollinsn@&#8203;gmail\.com wrote​:

Fixing this would probably resolve a few older bugs involving closing stdin/out/err and opening a new file as fd 0/1/2. On Jul 10\, 2016 10​:07\, "Aaron Crane" \perlbug\-followup@&#8203;perl\.org wrote​:

# New Ticket Created by Aaron Crane # Please include the string​: [perl #128591] # in the subject line of all future correspondence about this issue. # \<URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=128591 >

Perl refuses to even try to read from STDOUT or write to STDIN\, even if the underlying file descriptors are readable and/or writable as appropriate.

I originally observed this using a dup'ed STDOUT​: a forked process wrote data to stdout\, and I wanted to be able to re-read that data after the child exited​:

open STDOUT\, "\+>"\, $file or die;
system 'generate\_output';
seek STDOUT\, 0\, 0 or die;
\<STDOUT>// die;

The readline emits a "Filehandle STDOUT opened only for output" warning\, and yields undef.

My first thought was that dup'ing filehandles should copy the PERLIO_F_CANREAD and PERLIO_F_CANWRITE flags from the original handle to the new one. But that actually isn't sufficient​: it's possible for Perl to be started with a readable stdout and/or a writable stdin​:

$ perl \-we '\<STDOUT> // die' 1\<> /dev/null
Filehandle STDOUT opened only for output at \-e line 1\.
Died at \-e line 1\.
$ perl \-we 'STDIN\->print\("\\n"\) // die' 0\<> /dev/null
Filehandle STDIN opened only for input at

/Users/aaron/perl5/perlbrew/perls/perl-5.24.0/lib/5.24.0/darwin-2level/IO/Handle.pm line 420. Died at -e line 1

Running those commands under "strace -e trace=read\,write" demonstrates that Perl makes no attempt to read from fd 1 or write to fd 0.

Perhaps the simplest fix would be to stop checking those flags before reading from or writing to a filehandle; we can expect the OS to yield EBADF iff the requested action is actually impossible.

Alternatively\, the flags should be set correctly on any handle that's either dup'ed\, or opened using the moral equivalent of fdopen (including the standard filehandles). That presumably involves using fcntl(F_GETFL) on the underlying descriptors in those cases.

-- Aaron Crane ** http​://aaroncrane.co.uk/

p5pRT commented 8 years ago

From @arc

Not directly\, at least as far as I can tell; at the very least\, fixing this by removing the CANREAD and CANWRITE tests wouldn't affect that at all. However\, someone with more knowledge of perlio may be able to say whether a smarter fix for this issue would touch the same parts of the codebase.

Chad Granum \exodist7@&#8203;gmail\.com wrote​:

Is this at all connected to https://rt-archive.perl.org/perl5/Ticket/Display.html?id=128530

On Jul 10\, 2016 10​:15 AM\, "Dan Collins" \dcollinsn@&#8203;gmail\.com wrote​:

Fixing this would probably resolve a few older bugs involving closing stdin/out/err and opening a new file as fd 0/1/2.

On Jul 10\, 2016 10​:07\, "Aaron Crane" \perlbug\-followup@&#8203;perl\.org wrote​:

# New Ticket Created by Aaron Crane # Please include the string​: [perl #128591] # in the subject line of all future correspondence about this issue. # \<URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=128591 >

Perl refuses to even try to read from STDOUT or write to STDIN\, even if the underlying file descriptors are readable and/or writable as appropriate.

I originally observed this using a dup'ed STDOUT​: a forked process wrote data to stdout\, and I wanted to be able to re-read that data after the child exited​:

open STDOUT\, "\+>"\, $file or die;
system 'generate\_output';
seek STDOUT\, 0\, 0 or die;
\<STDOUT>// die;

The readline emits a "Filehandle STDOUT opened only for output" warning\, and yields undef.

My first thought was that dup'ing filehandles should copy the PERLIO_F_CANREAD and PERLIO_F_CANWRITE flags from the original handle to the new one. But that actually isn't sufficient​: it's possible for Perl to be started with a readable stdout and/or a writable stdin​:

$ perl \-we '\<STDOUT> // die' 1\<> /dev/null
Filehandle STDOUT opened only for output at \-e line 1\.
Died at \-e line 1\.
$ perl \-we 'STDIN\->print\("\\n"\) // die' 0\<> /dev/null
Filehandle STDIN opened only for input at

/Users/aaron/perl5/perlbrew/perls/perl-5.24.0/lib/5.24.0/darwin-2level/IO/Handle.pm line 420. Died at -e line 1

Running those commands under "strace -e trace=read\,write" demonstrates that Perl makes no attempt to read from fd 1 or write to fd 0.

Perhaps the simplest fix would be to stop checking those flags before reading from or writing to a filehandle; we can expect the OS to yield EBADF iff the requested action is actually impossible.

Alternatively\, the flags should be set correctly on any handle that's either dup'ed\, or opened using the moral equivalent of fdopen (including the standard filehandles). That presumably involves using fcntl(F_GETFL) on the underlying descriptors in those cases.

-- Aaron Crane ** http​://aaroncrane.co.uk/

-- Aaron Crane ** http​://aaroncrane.co.uk/