Bug#1016369: IO::Handle ->error does not work, always saying "fine"

Damyan Ivanov dmn at debian.org
Sun Jul 31 09:37:09 BST 2022


-=| Ian Jackson, 30.07.2022 13:42:05 +0100 |=-
> Package: perl
> Version: 5.34.0-4
> Severity: grave
> 
> To reproduce
> 
>     perl -MIO::Handle -e 'open X, "<", "." or die $!; $_ = <X>; printf "%s %s %s\n", X->error(), $!;'
>     perl -MIO::Handle -e 'open X, ">", "/dev/full" or die $!; print X 1; flush X; printf "%s %s %s\n", X->error(), $!; close X'
> 
> Expected output
> 
>     -1 Bad file descriptor
>     -1 No space left on device
> 
> Actual output
> 
>     0 Bad file descriptor
>     0 No space left on device

Thanks for the reproducer. I have converted it to a test file and have 
run that on all perl versions from blead back to 5.6.2, thanks to 
perlbrew.

Here's the test file:
===========================================================
$ cat 1016369.t
use Test::More;

plan skip_all => "IO::Handle not available" unless eval 'use IO::Handle; 1';

open(X, "<", ".") or die $!;
ok(!defined(<X>), 'failed reading from ".", as expected');
ok(X->error,      'X->error is TRUE after reading from "."');
close X;

SKIP: {
    skip "/dev/full not available", 3 unless -w '/dev/full';

    open X, '>', '/dev/full' or die $!;
    ok((print X "1"), "successful write to /dev/full");
    ok(!X->flush,     "flush after writing to /dev/full fails");
    ok(X->error,      "X->error is TRUE after flushing /dev/full");
    close X;
}

done_testing;
======================================================

Digested results of `prove 1016369.t`:

'X->error is TRUE after reading from "."': all versions fail

'X->error is TRUE after flushing /dev/full': blead, 5.36.0, 5.34.3 and 
5.6.2 pass, 5.32.1 through 5.8.9 fail

> This is quite alarming.  I think it makes it in fact impossible to
> read files fully reliably in Perl.

On the other hand, it went unnoticed for many years, so it can't be 
that bad.

Note that the recommended way to read files line by line is (perldoc 
-f readline):

    while ( ! eof($fh) ) {
        defined( $_ = readline $fh ) or die "readline failed: $!";
        ...
    }

This may explain why the X->error misbehaviour wasn't detected for so 
long.

> "use autodie" does not seem to help.

I think this is expected. autodie replaces the functional interface, 
lexically, not the OO one provided by IO::Handle.

> And scripts might reasonably have expected that they could defer 
> error handling by testing error() rather than each call (as one can 
> in C).

Here I concur. The behaviour of X->error is wrong and needs fixing.

> I think this used to work, but, evidently, only in the distant past,
> since my jessie chroot doesn't get this right either.

This part was what inspired my archaeological tests above. 5.6.2 was 
indeed far in the past.

> Justification for the severity:
> 
> Can cause data loss: if a file is opened but unreadable for any
> reason, the program will process the part (if any) that will is
> readable and then 

I'd use 'important' to signal that it would be nice to get this fixed 
in stable and that the package is still quite useful, but this is for 
Niko and Dominic to decide. Perhaps it doesn't matter so much in the 
end, since perl is Essential:yes.


-- Damyan




More information about the Perl-maintainers mailing list