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

PerlIO refuses to read STDOUT or write STDIN #15434

Open
p5pRT opened this issue Jul 10, 2016 · 5 comments
Open

PerlIO refuses to read STDOUT or write STDIN #15434

p5pRT opened this issue Jul 10, 2016 · 5 comments

Comments

@p5pRT
Copy link

p5pRT commented Jul 10, 2016

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

Searchable as RT128591$

@p5pRT
Copy link
Author

p5pRT commented Jul 10, 2016

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;
  <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
Copy link
Author

p5pRT commented Jul 10, 2016

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@​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
Copy link
Author

p5pRT commented Jul 10, 2016

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

@p5pRT
Copy link
Author

p5pRT commented Jul 10, 2016

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@​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@​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
Copy link
Author

p5pRT commented Jul 10, 2016

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@​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@​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@​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/

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