Open p5pRT opened 17 years ago
This is a bug report for perl from perlbug@der-pepe.de\, generated with the help of perlbug 1.35 running under perl v5.8.8.
-----------------------------------------------------------------
open STDOUT\, '>/dev/full' or die $!; $|++; for (0..2) { print 'x' or warn $!; open my $f\, '\</no/path/to/file'; }
This script should print "No space left on device" three times (because this is what you get for writing to /dev/full.) However\, what it does print is this:
No space left on device at bug.pl line 4. No such file or directory at bug.pl line 4. No such file or directory at bug.pl line 4.
It seems that once "open" sets $! to "No such file or directory"\, "print" doesn't change $! any more even if it fails.
(The script only runs on Unix variants because of the /dev/full thing.)
I've tried strace-ing this\, and I found that buffering somehow gets re-enabled. These are the relevant system calls\, in order:
write(1\, "x"\, 1) = -1 ENOSPC (No space left on device) write(2\, "No space left on device at bug.p"...\, 42) = 42 open("/no/path/to/file"\, O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory) open("/no/path/to/file"\, O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory) open("/no/path/to/file"\, O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory) write(1\, "xx"\, 2) = -1 ENOSPC (No space left on device)
Even if I include $|=1 in the loop just before "print"\, the "xx" is not printed seperatedly.
On Thu\, 31 May 2007 18:39:08 -0700\, "perlbug@der-pepe.de (via RT)" \perlbug\-followup@​perl\.org wrote:
# New Ticket Created by perlbug@der-pepe.de # Please include the string: [perl #43097] # in the subject line of all future correspondence about this issue. # \<URL: http://rt.perl.org/rt3/Ticket/Display.html?id=43097 >
This is a bug report for perl from perlbug@der-pepe.de\, generated with the help of perlbug 1.35 running under perl v5.8.8.
-----------------------------------------------------------------
open STDOUT\, '>/dev/full' or die $!; $|++; for (0..2) { print 'x' or warn $!; open my $f\, '\</no/path/to/file'; }
This script should print "No space left on device" three times (because this is what you get for writing to /dev/full.) However\, what it does print is this:
No space left on device at bug.pl line 4. No such file or directory at bug.pl line 4. No such file or directory at bug.pl line 4.
from perldoc perlvar: --8\<--- $! If used numerically\, yields the current value of the C "errno" variable\, or in other words\, if a system or library call fails\, it sets this variable. This means that the value of $! is meaningful only immediately after a failure: -->8---
the key here is *only immediately after the failure*. The last *system* failure in the second and third line was the fail open to the lexical handle. IMHO not a bug.
It seems that once "open" sets $! to "No such file or directory"\, "print" doesn't change $! any more even if it fails.
(The script only runs on Unix variants because of the /dev/full thing.)
-- H.Merijn Brand Amsterdam Perl Mongers (http://amsterdam.pm.org/) using & porting perl 5.6.2\, 5.8.x\, 5.9.x on HP-UX 10.20\, 11.00\, 11.11\, & 11.23\, SuSE 10.0 & 10.2\, AIX 4.3 & 5.2\, and Cygwin. http://qa.perl.org http://mirrors.develooper.com/hpux/ http://www.test-smoke.org http://www.goldmark.org/jeff/stupid-disclaimers/
The RT System itself - Status changed from 'new' to 'open'
On 6/1/07\, H.Merijn Brand \h\.m\.brand@​xs4all\.nl wrote:
On Thu\, 31 May 2007 18:39:08 -0700\, "perlbug@der-pepe.de (via RT)" \perlbug\-followup@​perl\.org wrote:
# New Ticket Created by perlbug@der-pepe.de # Please include the string: [perl #43097] # in the subject line of all future correspondence about this issue. # \<URL: http://rt.perl.org/rt3/Ticket/Display.html?id=43097 >
This is a bug report for perl from perlbug@der-pepe.de\, generated with the help of perlbug 1.35 running under perl v5.8.8.
-----------------------------------------------------------------
open STDOUT\, '>/dev/full' or die $!; $|++; for (0..2) { print 'x' or warn $!; open my $f\, '\</no/path/to/file'; }
This script should print "No space left on device" three times (because this is what you get for writing to /dev/full.) However\, what it does print is this:
No space left on device at bug.pl line 4. No such file or directory at bug.pl line 4. No such file or directory at bug.pl line 4.
from perldoc perlvar: --8\<--- $! If used numerically\, yields the current value of the C "errno" variable\, or in other words\, if a system or library call fails\, it sets this variable. This means that the value of $! is meaningful only immediately after a failure: -->8---
the key here is *only immediately after the failure*. The last *system* failure in the second and third line was the fail open to the lexical handle. IMHO not a bug.
Since stdout is autoflushing each call to print should result in a system call which because of the magic of /dev/full should fail. Therefore it looks to me like it is a bug.
yves
-- perl -Mre=debug -e "/just|another|perl|hacker/"
open STDOUT\, '>/dev/full' or die $!; $|++; for (0..2) { print 'x' or warn $!; open my $f\, '\</no/path/to/file'; }
This script should print "No space left on device" three times (because this is what you get for writing to /dev/full.) However\, what it does print is this:
No space left on device at bug.pl line 4. No such file or directory at bug.pl line 4. No such file or directory at bug.pl line 4.
This bug is still in perl 5.8.8 and 5.10.0 and blead.
I think I have fixed this bug. After giving this careful thought\, I think that the patch below is the proper way to fix this; but I would appreciate feedback from someone with more experience.
The problem is:
pp_print calls do_print. If that is successful *and* the file-handle is autoflushing\, pp_print calls PerlIO_flush. The success of do_print depends on the handle's error flag\, which gets set when a flush fails and will never be cleared again when writing into the buffer; that means the filehandle will never be flushed again (until the buffer fills up). My fix simply clears the error flag before each write.
This has another implication: When you get an error from print and then print an empty string\, the second print will be successful. This hasn't been the case previously\, but I think it's the right behaviour.
I've also added tests for both the $! thing and the empty-string thing.
The tests don't use /dev/full as in the original report because I don't think that would be portable. Instead they produce a print error by printing to a closed pipe.
Regards\, Christoph
On Aug 18\, 2008\, at 18:40\, Christoph Bussenius via RT wrote:
open STDOUT\, '>/dev/full' or die $!; $|++; for (0..2) { print 'x' or warn $!; open my $f\, '\</no/path/to/file'; }
Is there any significance to the 'open my $f' statement here?
This script should print "No space left on device" three times (because this is what you get for writing to /dev/full.) However\,
what it does print is this:No space left on device at bug.pl line 4. No such file or directory at bug.pl line 4. No such file or directory at bug.pl line 4.
This bug is still in perl 5.8.8 and 5.10.0 and blead.
I think I have fixed this bug. After giving this careful thought\, I think that the patch below is the proper way to fix this; but I would appreciate feedback from someone with more experience.
I don't think the patch is acceptable. If print fails the error
condition need to stay around until close() time. It's common to
just use print without testing its outcome and then in the end verify
that all prints succeeded by testing if close() is successful.
open(my $fh\, ">"\, $file) || die "Can't open $file: $!"; print $fh $buf; print $fh $buf; ... close($fh) || die "Can't write to $file: $!";
With your patch the first print could fail and then the second could
succeed; leading to close() not reporting the first error.
--Gisle
The problem is:
pp_print calls do_print. If that is successful *and* the file- handle is autoflushing\, pp_print calls PerlIO_flush. The success of do_print depends on the handle's error flag\, which gets set when a flush fails and will never be cleared again when writing
into the buffer; that means the filehandle will never be flushed again
(until the buffer fills up). My fix simply clears the error flag before each write.This has another implication: When you get an error from print and
then print an empty string\, the second print will be successful. This
hasn't been the case previously\, but I think it's the right behaviour.I've also added tests for both the $! thing and the empty-string
thing.The tests don't use /dev/full as in the original report because I
don't think that would be portable. Instead they produce a print error by printing to a closed pipe.Regards\, Christoph
\
On Tue\, Aug 19\, 2008 at 09:45:24AM +0200\, Gisle Aas wrote:
On Aug 18\, 2008\, at 18:40\, Christoph Bussenius via RT wrote:
open STDOUT\, '>/dev/full' or die $!; $|++; for (0..2) { print 'x' or warn $!; open my $f\, '\</no/path/to/file'; }
Is there any significance to the 'open my $f' statement here?
Yes\, it sets $! to ENOENT (No such file or directory)\, to demonstrate that print fails to reset $! to ENOSPC (No space left on device)\, as shown in the triple-quoted message:
This script should print "No space left on device" three times (because this is what you get for writing to /dev/full.) However\, what it does print is this:
No space left on device at bug.pl line 4. No such file or directory at bug.pl line 4. No such file or directory at bug.pl line 4.
(This was my original report for bug #43097).
I don't think the patch is acceptable. If print fails the error condition need to stay around until close() time. It's common to just use print without testing its outcome and then in the end verify that all prints succeeded by testing if close() is successful.
open\(my $fh\, ">"\, $file\) || die "Can't open $file​: $\!"; print $fh $buf; print $fh $buf; \.\.\. close\($fh\) || die "Can't write to $file​: $\!";
With your patch the first print could fail and then the second could succeed; leading to close() not reporting the first error.
Hm\, I see your point. I'll think about it\, thanks.
Christoph
On Aug 18\, 2008\, at 18:40\, Christoph Bussenius via RT wrote:
pp_print calls do_print. If that is successful *and* the file-handle is autoflushing\, pp_print calls PerlIO_flush. The success of do_print depends on the handle's error flag\, which gets set when a flush fails and will never be cleared again when writing into the buffer; that means the filehandle will never be flushed again (until the buffer fills up). My fix simply clears the error flag before each write.
I've added a new patch below. Instead of clearing the error flag\, it will now avoid to consider the previous error flag for the return status of do_print. This fixes the bug and still keeps the error flag so that close knows about previous errors.
On Tue\, Aug 19\, 2008 at 09:45:24AM +0200\, Gisle Aas wrote:
It's common to just use print without testing its outcome and then in the end verify that all prints succeeded by testing if close() is successful.
open\(my $fh\, ">"\, $file\) || die "Can't open $file​: $\!"; print $fh $buf; print $fh $buf; \.\.\. close\($fh\) || die "Can't write to $file​: $\!";
With your patch the first print could fail and then the second could succeed; leading to close() not reporting the first error.
This piece of code is still a bit problematic in my opinion. In close's error message\, $! is not guaranteed to describe the error that happened. If an error happens (as you suggest) in the first print\, $! will be something like "no space left on device". However\, in the passage you marked as "..."\, $! can end up with any strange error code\, and so the error that gets reported may not have anything to do with writing to the file.
I think the only way to get this to work properly is to save errno along with the error flag for every PerlIO handle.
Regards\, Christoph
On Mon Sep 08 04:07:40 2008\, lists@der-pepe.de wrote:
On Aug 18\, 2008\, at 18:40\, Christoph Bussenius via RT wrote:
pp_print calls do_print. If that is successful *and* the file-handle is autoflushing\, pp_print calls PerlIO_flush. The success of do_print depends on the handle's error flag\, which gets set when a flush fails and will never be cleared again when writing into the buffer; that means the filehandle will never be flushed again (until the buffer fills up). My fix simply clears the error flag before each write.
I've added a new patch below. Instead of clearing the error flag\, it will now avoid to consider the previous error flag for the return status of do_print. This fixes the bug and still keeps the error flag so that close knows about previous errors.
On Tue\, Aug 19\, 2008 at 09:45:24AM +0200\, Gisle Aas wrote:
It's common to just use print without testing its outcome and then in the end verify that all prints succeeded by testing if close() is successful.
open\(my $fh\, ">"\, $file\) || die "Can't open $file​: $\!"; print $fh $buf; print $fh $buf; \.\.\. close\($fh\) || die "Can't write to $file​: $\!";
With your patch the first print could fail and then the second could succeed; leading to close() not reporting the first error.
This piece of code is still a bit problematic in my opinion. In close's error message\, $! is not guaranteed to describe the error that happened. If an error happens (as you suggest) in the first print\, $! will be something like "no space left on device". However\, in the passage you marked as "..."\, $! can end up with any strange error code\, and so the error that gets reported may not have anything to do with writing to the file.
I think the only way to get this to work properly is to save errno along with the error flag for every PerlIO handle.
Regards\, Christoph
--- perl-5.10.0/doio.c 2007-12-18 11:47:07.000000000 +0100 +++ perl-5.10.0-debug/doio.c 2008-09-08 12:32:57.325273275 +0200 @@ -1247\,7 +1247\,7 @@ if (len && (PerlIO_write(fp\,tmps\,len) == 0)) happy = FALSE; Safefree(tmpbuf); - return happy ? !PerlIO_error(fp) : FALSE; + return happy; } }
I believe this change is dangerous under the following circumstances:
- no autoflush to a full filesystem - program calls print() until the buffer fills\, at which point flush is called\, which fails\, setting the error flags. Note that the final write may only be partly copied to the buffer - file space is freed up - the next write forces a flush\, which writes the buffer with a possibly truncated final write to the file system - the new content is then written to the buffer (possibly flushing)\, and so on with new writes
This produces output with some content missing.
A patch that saves errno per file handle would be less dangerous\, but I don't know if we want perlio to go to that level to preserve error codes.
Tony
Migrated from rt.perl.org#43097 (status was 'open')
Searchable as RT43097$