develooper Front page | perl.perl5.porters | Postings from March 2001

Re: [ID 20000913.003] Closing STDERR leaves fd(2) marked w/o?

Thread Previous | Thread Next
Warren Hyde
March 14, 2001 08:59
Re: [ID 20000913.003] Closing STDERR leaves fd(2) marked w/o?
Message ID:
Perl Porters:

Since no action seems to have been taken on this bug, let me rephrase it
and call it two separate bugs in Perl 5.6.0.


File descriptors 1 and 2 are always assumed to be opened only for output,
and produce a new warning when they are closed and re-opened for input.
Here's a small program showing this bug:


#!/usr/local/bin/perl5.6.0 -w

close STDOUT;
select STDERR; # Since we closed STDOUT
open FOOBAR, "</etc/motd"; # opened for INPUT on descriptor 1

printf "STDOUT file descriptor is %s\n",
    defined fileno STDOUT ? fileno STDOUT : "closed";
printf "FOOBAR file descriptor is %s\n",
    defined fileno FOOBAR ? fileno FOOBAR : "closed";

my $junk = <FOOBAR>;


And... here's the output it produces:

STDOUT file descriptor is closed
FOOBAR file descriptor is 1
Filehandle main::FOOBAR opened only for output at ./perlbug1 line 12.

Obviously, main::FOOBAR is opened for INPUT, as seen in the open statement,
and Perl is not quite registering the fact that we have closed STDOUT and
re-used file descriptor 1 as an input source.  Please note that the above
bug also affects STDERR, which may be closed and file descriptor 2 re-used
as an input source also.


Warning/Error text always gets sent to file descriptor 2, and not STDERR,
as advertised.  The documentation for "warn" and "die" say this:

    warn LIST
            Produces a message on STDERR just like `die', but doesn't exit
            or throw an exception...
    die LIST
            Outside an `eval', prints the value of LIST to `STDERR' and
            exits with the current value of `$!' (errno)...

Begging to differ, I assert that the output does NOT go to STDERR, but it
really goes to file descriptor 2, whatever that may be, and whether or not
it is opened as an input or output source.

I would assert that the warn/die mechanism should check whether STDERR has
a file descriptor, and do absolutely NOTHING if it does not.  Touching file
descriptor 2 arbitrarily is a BAD THING since you don't know what it is, or
how it needs to be used.  In my case, it was opened as a pipe to a program
feeding it data, and the act of writing the warning message to the pipe did
some very bad things.

I hope this clarifies this bug report enough to help you track it down.

Quoting Warren Hyde (
> This is a bug report for perl from,
> generated with the help of perlbug 1.28 running under perl v5.6.0.
> -----------------------------------------------------------------
> [Please enter your report here]
> With warnings enabled (via '-w' or $^W=1), perl always assumes that
> file descriptors #1 and #2 will be opened on STDOUT and STDERR, and
> furthermore that they will be write-only.
> If the user closes either STDOUT or STDERR, then re-openes them for
> reading on a file or pipe, it causes a warning to be generated and
> this warning is sent to file descriptor #2 even if STDERR had been
> previously closed.
> Now, if descriptor #2 is a readable pipe, it has the effect of killing
> the pipe which clobbers any input it had to be read (since the warning
> could not be sent to the pipe).
> Once STDERR is closed, it should disable any warnings from being generated
> in the first place because, obviously, there is nowhere left to send them.
> Continuing to send them to file descriptor #2 is just plain bad, because
> Perl has no control over what is opened on that file descriptor.
> This bug only affects perl5.6.0 and no previous versions (of Perl 5).
> I have verified this assertion with the following perl versions:
>     PASS perl5.002
>     PASS perl5.003
>     PASS perl5.004
>     PASS perl5.00502
>     PASS perl5.00503
>     FAIL perl5.6.0
> Here is the code which will illustrate the bug, with the specific example
> of showing how once STDOUT is closed, you cannot assume that file descriptor
> #1 should be write-only:
> =cut
> #!/usr/local/bin/perl
> # First, close STDOUT, which should free up file descriptor #1
> close STDOUT;
> # Select STDERR as default destination for print statements.
> select STDERR;
> # Next, open a file for reading which inherits file descriptor #1
> open FOOBAR, "</etc/motd";
> # Read from and exhaust the file
> print "#### BEGIN WITHOUT WARNINGS\n";
> print (<FOOBAR>);
> print "#### END\n";
> close FOOBAR;
> # Now, enable WARNINGS and do it all again
> $^W=1; 
> # Open another file for reading which inherits file descriptor #1
> open FOOBAR, "</etc/motd";
> # Read from and exhaust the file
> print "#### BEGIN WITH WARNINGS\n";
> print (<FOOBAR>);
> print "#### END\n";
> close FOOBAR;
> __END__
> [Please do not change anything below this line]
> -----------------------------------------------------------------
> ---
> Flags:
>     category=core
>     severity=high
> ---
> Site configuration information for perl v5.6.0:
> Configured by whyde at Wed Apr 19 10:49:42 CDT 2000.
> Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration:
>   Platform:
>     osname=solaris, osvers=2.6, archname=sun4-solaris
>     uname='sunos beecave 5.6 generic_105181-16 sun4u sparc '
>     config_args='-Dcc=gcc'
>     hint=recommended, useposix=true, d_sigaction=define
>     usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef
>     useperlio=undef d_sfio=undef uselargefiles=define 
>     use64bitint=undef use64bitall=undef uselongdouble=undef usesocks=undef
>   Compiler:
>     cc='gcc', optimize='-O', gccversion=2.95.2 19991024 (release)
>     cppflags='-fno-strict-aliasing -I/usr/local/include'
>     ccflags ='-fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
>     stdchar='unsigned char', d_stdstdio=define, usevfork=false
>     intsize=4, longsize=4, ptrsize=4, doublesize=8
>     d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
>     ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
>     alignbytes=8, usemymalloc=y, prototype=define
>   Linker and Libraries:
>     ld='gcc', ldflags =' -L/usr/local/lib '
>     libpth=/usr/local/lib /lib /usr/lib /usr/ccs/lib
>     libs=-lsocket -lnsl -ldb -ldl -lm -lc -lcrypt -lsec
>     libc=/lib/, so=so, useshrplib=false, libperl=libperl.a
>   Dynamic Linking:
>     dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags=' '
>     cccdlflags='-fPIC', lddlflags='-G -L/usr/local/lib'
> Locally applied patches:
> ---
> @INC for perl v5.6.0:
>     /usr/local/lib/perl5/5.6.0/sun4-solaris
>     /usr/local/lib/perl5/5.6.0
>     /usr/local/lib/perl5/site_perl/5.6.0/sun4-solaris
>     /usr/local/lib/perl5/site_perl/5.6.0
>     /usr/local/lib/perl5/site_perl/5.005/sun4-solaris
>     /usr/local/lib/perl5/site_perl/5.005
>     /usr/local/lib/perl5/site_perl
>     .
> ---
> Environment for perl v5.6.0:
>     HOME=/home/whyde
>     LANG=C
>     LANGUAGE (unset)
>     LD_LIBRARY_PATH=/usr/X11/lib3d:/usr/X11/lib:/usr/openwin/lib:/usr/dt/lib:/usr/lib:/usr/local/lib
>     LOGDIR (unset)
>     PATH=/usr/X11/bin:/usr/openwin/bin:/usr/dt/bin:/usr/local/scripts:/usr/local/bin:/usr/ucb:/bin:/sbin:/etc:/usr/bin:/usr/sbin:/usr/ccs/bin:/usr/etc:/home/whyde/bin:.:/wcp/local/scripts:/wcp/local/bin:/home/whyde/wcp/tools/scripts:/wcp/tools/scripts:/wcp/tools/scripts
>     PERL_BADLANG (unset)
>     SHELL=/usr/local/bin/tcsh

"A mistake is an opprotunity the full value of which we have yet to realize."
    --Edwin Land

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About