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

IO::Handle's error() method does not accurately reflect write errors #12783

Open
p5pRT opened this issue Feb 17, 2013 · 5 comments
Open

IO::Handle's error() method does not accurately reflect write errors #12783

p5pRT opened this issue Feb 17, 2013 · 5 comments

Comments

@p5pRT
Copy link

p5pRT commented Feb 17, 2013

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

Searchable as RT116807$

@p5pRT
Copy link
Author

p5pRT commented Feb 17, 2013

From tchrist@perl.com

The documentation for IO​::Handle reads​:

  $io->error
  Returns a true value if the given handle has experienced any errors
  since it was opened or since the last call to "clearerr", or if the
  handle is invalid. It only returns false for a valid handle with no
  outstanding errors.

However, this is not true. For example, a failed write on a given handle
can set errno to ENOSPC, yet fail to be noted by the error() method on that
handle. This is shown by the enclosed test script, which is designed to
trigger an error on the write. You can tell that there is a bug because
it emits​:

  syswrite failed, errno was ENOSPC (28)​: No space left on device
  ERROR​: path_fh is not in an error state after failed syswrite.

Tested on v5.8.8 up through blead.

--tom

#!/usr/bin/env perl

use v5.6;
use strict;
use warnings;
use warnings FATAL => qw(deprecated closure syntax);
use sigtrap;

use Carp;
use Errno;
use Fcntl;
use IO​::Handle;

use constant {
  # this is only needed if /dev/full isn't around
  FILE_ON_FULL_FILESYSTEM => "/Volumes/TCHRISTFOB1/full/bar",
};

main();
exit();

sub main {
  local $SIG{__WARN__} = sub { confess "fatalized warning @​_" };
  STDOUT->autoflush(1);
  test_file();
  print "\nThat's all, folks!\n";
}

##########################################################################

sub test_file {
  my $file = (-c "/dev/full") ? "/dev/full" : FILE_ON_FULL_FILESYSTEM;
  test_write($file);
}

sub test_write {
  my($path_name, $is_big) = @​_;
  my $path_fh;

  my $reopen = sub {
  $path_fh = undef;

  sysopen($path_fh, $path_name, O_WRONLY | O_APPEND)
  || confess "can't sysopen $path_name​: $!";
  print "opened $path_name for append\n";
  binmode($path_fh);
  $path_fh->autoflush(1);
  };

  my $string = "[this is the line of test data]\n";
  if ($is_big) {
  $string x= 1_000;
  }

  my $slen = length($string);

  print "\ntesting syswrite\n";

  &$reopen;

  my $written = syswrite($path_fh, $string, $slen);
  if (defined $written) {
  print "ERROR​: expected write to fail, but syswrote $written bytes\n\n";
  if ($written != $slen) {
  print "But I wanted to write $slen bytes.\n";
  }
  } else {
  my $errno = $! || confess "expected errno";
  my $has_error = $path_fh->error;
  print "syswrite failed, errno was ", fmt_errno($errno), "\n";
  if (my $has_error = $path_fh->error) {
  print "path_fh error was ", fmt_bool($has_error), "\n";
  } else {
  print "ERROR​: path_fh is not in an error state after failed syswrite.\n";
  }
  }
  my $good_writes = defined($written);

  my $reclose = sub {
  if (close($path_fh)) {
  if ($good_writes) {
  print "correctly closed $path_name\n";
  } else {
  print "ERROR​: expected close to fail, since writing failed\n";
  }
  } else {
  if ($good_writes) {
  print "ERROR​: expected good close, but't close $path_name​: ",
  fmt_errno($!), "\n";
  } else {
  print "As expected with write errors, can't close $path_name​: ",
  fmt_errno($!), "\n";
  }
  }
  };
  &$reclose;

  &$reopen;
  print "\ntesting print\n";

  my $ok = print $path_fh $string;
  if ($ok) {
  print "ERROR​: Print of $slen successful.\n";
  }
  else {
  my $errno = $! || confess "expected errno";
  my $has_error = $path_fh->error;
  print "print failed, errno was ", fmt_errno($errno), "\n";

  if ($has_error) {
  print "path_fh error was ", fmt_bool($has_error), "\n";
  } else {
  print "ERROR​: path_fh is not in an error state after failed print.\n";
  }
  }

  $good_writes = $ok;
  &$reclose;

}

sub fmt_bool {
  my($bool) = @​_;
  return $bool ? "TRUE" : "FALSE";
}

sub fmt_undef {
  my($scalar) = @​_;
  return defined($scalar) ? $scalar : "UNDEF";
}

BEGIN {

  my @​_Errno2Sym;
  for my $errname ( grep /^E\p{Lu}+$/, @​Errno​::EXPORT_OK ) {
  my $errnum = do {
  no strict "refs";
  &{"Errno​::$errname"};
  };
  $_Errno2Sym[$errnum] = $errname;
  }

  sub fmt_errno {
  my $num = 0 + $_[0];
  my $strerror = do {
  local $! = $num;
  "$!";
  };
  my $esym = $_Errno2Sym[$num] || "unknown error number #$num";
  return "$esym ($num)​: $strerror";
  }

}

__END__

testing syswrite
opened /Volumes/TCHRISTFOB1/full/bar for append
syswrite failed, errno was ENOSPC (28)​: No space left on device
ERROR​: path_fh is not in an error state after failed syswrite.
ERROR​: expected close to fail, since writing failed
opened /Volumes/TCHRISTFOB1/full/bar for append

testing print
print failed, errno was ENOSPC (28)​: No space left on device
path_fh error was TRUE
As expected with write errors, can't close /Volumes/TCHRISTFOB1/full/bar​: ENOSPC (28)​: No space left on device

That's all, folks!

================================================================

Summary of my perl5 (revision 5 version 16 subversion 0) configuration​:

  Platform​:
  osname=darwin, osvers=9.8.0, archname=darwin-2level
  uname='darwin tom-christiansens-macbook-pro-2.local 9.8.0 darwin kernel version 9.8.0​: wed jul 15 16​:55​:01 pdt 2009; root​:xnu-1228.15.4~1release_i386 i386 '
  config_args=''
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=undef, usemultiplicity=undef
  useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
  use64bitint=undef, use64bitall=undef, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -I/opt/local/include',
  optimize='-O3',
  cppflags='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -I/opt/local/include'
  ccversion='', gccversion='4.0.1 (Apple Inc. build 5493)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
  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, prototype=define
  Linker and Libraries​:
  ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags =' -fstack-protector -L/usr/local/lib -L/opt/local/lib'
  libpth=/usr/local/lib /opt/local/lib /usr/lib
  libs=-lgdbm -ldbm -ldb -ldl -lm -lutil -lc
  perllibs=-ldl -lm -lutil -lc
  libc=, so=dylib, useshrplib=false, libperl=libperl.a
  gnulibc_version=''
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
  cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup -L/usr/local/lib -L/opt/local/lib -fstack-protector'

Characteristics of this binary (from libperl)​:
  Compile-time options​: HAS_TIMES PERLIO_LAYERS PERL_DONT_CREATE_GVSV
  PERL_MALLOC_WRAP PERL_PRESERVE_IVUV USE_LARGE_FILES
  USE_LOCALE USE_LOCALE_COLLATE USE_LOCALE_CTYPE
  USE_LOCALE_NUMERIC USE_PERLIO USE_PERL_ATOF
  Built under darwin
  Compiled at Jul 15 2012 13​:29​:37
  %ENV​:
  PERL_UNICODE="S"
  @​INC​:
  /usr/local/lib/perl5/site_perl/5.16.0/darwin-2level
  /usr/local/lib/perl5/site_perl/5.16.0
  /usr/local/lib/perl5/5.16.0/darwin-2level
  /usr/local/lib/perl5/5.16.0
  /usr/local/lib/perl5/site_perl/5.14.0
  /usr/local/lib/perl5/site_perl/5.13.9
  /usr/local/lib/perl5/site_perl/5.13.8
  /usr/local/lib/perl5/site_perl/5.13.0
  /usr/local/lib/perl5/site_perl/5.12.3
  /usr/local/lib/perl5/site_perl/5.12.2
  /usr/local/lib/perl5/site_perl/5.11.3
  /usr/local/lib/perl5/site_perl/5.10.0
  /usr/local/lib/perl5/site_perl
  .

@p5pRT
Copy link
Author

p5pRT commented Feb 23, 2013

From @jkeenan

On Sun Feb 17 15​:16​:54 2013, tom christiansen wrote​:

The documentation for IO​::Handle reads​:
...

Confirming that I got the same output as Tom on Linux/i386.

jimk

@p5pRT
Copy link
Author

p5pRT commented Feb 23, 2013

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

@xenu xenu removed the Severity Low label Dec 29, 2021
@tonycoz tonycoz added the Closable? We might be able to close this ticket, but we need to check with the reporter label Apr 11, 2024
@tonycoz
Copy link
Contributor

tonycoz commented Apr 11, 2024

I believe this was fixed by 89341f8 (which itself needed a fix in 8a2562b

@jkeenan
Copy link
Contributor

jkeenan commented Apr 14, 2024

I believe this was fixed by 89341f8 (which itself needed a fix in 8a2562b

I don't think so. Somewhat to my surprise, I found Tom's test program on my server exactly where I placed it 11 years ago. I ran it and got what appear to be the same results as I did then and as Tom did.

$ perl 116807_iohandle_write.pl 

testing syswrite
opened /dev/full for append
syswrite failed, errno was ENOSPC (28): No space left on device
ERROR: path_fh is not in an error state after failed syswrite.
ERROR: expected close to fail, since writing failed
opened /dev/full for append

testing print
print failed, errno was ENOSPC (28): No space left on device
path_fh error was TRUE
As expected with write errors, can't close /dev/full: ENOSPC (28): No space left on device

That's all, folks!

That suggests to me that the problem is still present, hence the ticket is not closable.

@jkeenan jkeenan removed the Closable? We might be able to close this ticket, but we need to check with the reporter label Apr 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants