Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.85k stars 524 forks source link

I/O problem with IO::Handle #1245

Closed p5pRT closed 19 years ago

p5pRT commented 24 years ago

Migrated from rt.perl.org#2236 (status was 'resolved')

Searchable as RT2236$

p5pRT commented 24 years ago

From manfredi@lod28.gnb.st.com

This is a bug report for perl from raphael.manfredi@​st.com\, generated with the help of perlbug 1.26 running under perl 5.00503.


I don't understand what's happening here​:

  1 use IO​::Handle;   2 use File​::stat;   3
  4 open(STDERR\, ">bug.stderr");   5
  6 $fn = fileno(\*main​::STDERR);   7 print "stderr at fd = #$fn\n";   8
  9 $h = IO​::Handle->new_from_fd(\*main​::STDERR\, "w");   10 print $h "to stderr?\n";   11 $h->print("to stderr again?\n");   12
  13 close STDERR;   14
  15 my $st = stat("bug.stderr");   16 printf "size = %d\n"\, $st->size;   17
  18 open(FILE\, "bug.stderr");   19 while (\) {   20 print;   21 }   22

When run\, this produces​:

  stderr at fd = #2   size = 0

If I now "cat bug.stderr"\, I get​:

  to stderr?   to stderr again?

which is correct.

It's not a File​::stat bug\, because if I move the test on line 15 before line 4\, I get the correct answer 28.



Site configuration information for perl 5.00503​:

Configured by manfredi at Mon Aug 9 12​:37​:05 MET DST 1999.

Summary of my perl5 (5.0 patchlevel 5 subversion 3) configuration​:   Platform​:   osname=solaris\, osvers=2.5.1\, archname=sun4-solaris   uname='sunos lod23 5.5.1 generic_103640-27 sun4u sparc sunw\,ultra-60 '   hint=previous\, useposix=true\, d_sigaction=define   usethreads=undef useperlio=define d_sfio=undef   Compiler​:   cc='/apa/SUNWspro/bin/cc'\, optimize='-O'\, gccversion=   cppflags='-I/home/manfredi/usr/BerkeleyDB/include'   ccflags ='-I/home/manfredi/usr/BerkeleyDB/include'   stdchar='unsigned char'\, d_stdstdio=define\, usevfork=true   intsize=4\, longsize=4\, ptrsize=4\, doublesize=8   d_longlong=define\, longlongsize=8\, d_longdbl=define\, longdblsize=16   alignbytes=8\, usemymalloc=y\, prototype=define   Linker and Libraries​:   ld='/apa/SUNWspro/bin/cc'\, ldflags ='-L/home/manfredi/usr/BerkeleyDB/lib'   libpth=/lib /usr/lib /usr/ccs/lib /home/manfredi/usr/BerkeleyDB/lib   libs=-lsocket -lnsl -ldl -lm -lc -lcrypt   libc=/lib/libc.so\, so=so\, useshrplib=false\, libperl=libperl.a   Dynamic Linking​:   dlsrc=dl_dlopen.xs\, dlext=so\, d_dlsymun=undef\, ccdlflags=' '   cccdlflags='-KPIC'\, lddlflags='-G -L/home/manfredi/usr/BerkeleyDB/lib'

Locally applied patches​:  


@​INC for perl 5.00503​:   /home/manfredi/usr/lib/perl   /home/manfredi/usr/lib/perl5/5.00503/sun4-solaris   /home/manfredi/usr/lib/perl5/5.00503   /home/manfredi/usr/lib/perl5/site_perl/5.005/sun4-solaris   /home/manfredi/usr/lib/perl5/site_perl/5.005   .


Environment for perl 5.00503​:   HOME=/home/manfredi   LANG=fr   LANGUAGE (unset)   LC_MESSAGES=C   LC_MONETARY=C   LC_NUMERIC=C   LC_TIME=C   LD_LIBRARY_PATH=/home/manfredi/usr/lib/X11​:/usr/openwin/lib   LOGDIR (unset)   PATH=/home/manfredi/bin/scripts​:/home/manfredi/bin/sun​:/home/manfredi/bin/sun/mh​:/home/manfredi/bin/scripts/mh​:/home/manfredi/bin/sun/fm2html​:/home/manfredi/bin/scripts/rdb​:/apa/gnu/SunOS5/bin​:/bin​:/usr/bin​:/sbin​:/usr/sbin​:/apa/SUNWspro/bin​:/usr/ccs/bin​:/usr/ucb​:/usr/contrib/bin​:/apa/comp/SunOS5/bin​:/apa/acroread/3.02/bin​:/apa/ddts/bin​:/apa/util/bin​:/etc​:/usr/bin/X11​:/usr/games​:/home/bruel/local/SunOS5/bin​:/home/manfredi​:.​:/home/manfredi/bin/acri   PERL_BADLANG (unset)   SHELL=/home/manfredi/bin/sun/ksh

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

On Mar 1\, Raphael Manfredi said​:

4    open\(STDERR\, ">bug\.stderr"\);

9    $h = IO​::Handle\->new\_from\_fd\(\\\*main​::STDERR\, "w"\);

10 print $h "to stderr?\n"; 11 $h->print("to stderr again?\n"); 12
13 close STDERR; 14
15 my $st = stat("bug.stderr"); 16 printf "size = %d\n"\, $st->size; 17
18 open(FILE\, "bug.stderr"); 19 while (\) { 20 print; 21 } 22

size = 0

Perhaps because the file is still open because you haven't done $h->close. You open the file twice (once with open() and once with new_from_fd()) and you open it for writing both times.

-- MIDN 4/C PINYAN\, NROTCURPI\, US Naval Reserve japhy@​pobox.com http​://www.pobox.com/~japhy/ http​://pinyaj.stu.rpi.edu/ PerlMonth - An Online Perl Magazine http​://www.perlmonth.com/ The Perl Archive - Articles\, Forums\, etc. http​://www.perlarchive.com/

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Quoting jeffp@​crusoe.net​: :Perhaps because the file is still open because you haven't done :$h->close. You open the file twice (once with open() and once with :new_from_fd()) and you open it for writing both times.

You're right.

So how does one create an IO​::* object that can be handled exactly via IO​::Handle would but WITHOUT fd-opening the file. Just to encapsulate a file descriptor in an OO framework.

Raphael

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Quoting jeffp@​crusoe.net​: ​:Perhaps because the file is still open because you haven't done ​:$h->close. You open the file twice (once with open() and once with ​:new_from_fd()) and you open it for writing both times.

You're right.

So how does one create an IO​::* object that can be handled exactly via IO​::Handle would but WITHOUT fd-opening the file. Just to encapsulate a file descriptor in an OO framework.

my $fh;

--tom

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

On Mar 1\, Raphael Manfredi said​:

So how does one create an IO​::* object that can be handled exactly via IO​::Handle would but WITHOUT fd-opening the file. Just to encapsulate a file descriptor in an OO framework.

Brute force?

  use IO​::Handle;   open FH\, ">file" or die "can't create file​: $!";   $obj = bless \*FH\, 'IO​::Handle';   $obj->print("test\n");   close FH; # or $obj->close;   print -s "file"; # better be 5

Or\, to make it look nicer (?)​:

  use IO​::Handle;   sub dup_from_fh (\*);

  $obj = dup_from_fh \*STDERR;

  sub dup_from_fh (\*) {   return bless shift\, 'IO​::Handle';   }

Or make it your own IO​::Handle method. Or whatever.

-- MIDN 4/C PINYAN\, NROTCURPI\, US Naval Reserve japhy@​pobox.com http​://www.pobox.com/~japhy/ http​://pinyaj.stu.rpi.edu/ PerlMonth - An Online Perl Magazine http​://www.perlmonth.com/ The Perl Archive - Articles\, Forums\, etc. http​://www.perlarchive.com/

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

my $fh;

--tom

Oy. As succinct as his signature.

  use IO​::Handle;   my $fh = \*FH;   $fh->print("sucker");

-- MIDN 4/C PINYAN\, NROTCURPI\, US Naval Reserve japhy@​pobox.com http​://www.pobox.com/~japhy/ http​://pinyaj.stu.rpi.edu/ PerlMonth - An Online Perl Magazine http​://www.perlmonth.com/ The Perl Archive - Articles\, Forums\, etc. http​://www.perlarchive.com/

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

use IO​::Handle; my $fh = \*FH; $fh->print("sucker");

I'm sorry\, Jeff\, but you're the sucker on this one\, for I must regretfully inform you that that code works fine. Apparently you aren't running the latest version of Perl. Please apply change #Change 2576 and try again.

But all this IO​::Handle object nonsense is just that​: nonsense. You don't need it\, and you don't want it. It's completely gratuitous\, and just a little bit deceptive.

Oh\, and your print just ran a good order of magnitude or two too slowly. Enjoy.

--tom

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

use IO​::Handle; my $fh = \*FH; $fh->print("sucker");

I'm sorry\, Jeff\, but you're the sucker on this one\, for I must regretfully inform you that that code works fine.

I wasn't doing "sucker" to say "no\, Tom\, you're wrong." I was saying it as a commentary to myself for writing all that dup_from_fh crap.

And that code didn't work for me\, now that I tried it (bad\, I know). 5.005_02 requires that $fh be blessed. But the latest Perl doesn't require that\, apparently. Cool.

But yeah\, I stick with real filehandles whenever possible.

-- MIDN 4/C PINYAN\, NROTCURPI\, US Naval Reserve japhy@​pobox.com http​://www.pobox.com/~japhy/ http​://pinyaj.stu.rpi.edu/ PerlMonth - An Online Perl Magazine http​://www.perlmonth.com/ The Perl Archive - Articles\, Forums\, etc. http​://www.perlarchive.com/

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Quoting tchrist@​chthon.perl.com​: :>So how does one create an IO​::* object that can be handled exactly :>via IO​::Handle would but WITHOUT fd-opening the file. Just to encapsulate :>a file descriptor in an OO framework. : :my $fh;

Yup\, that's what I would do normally. I don't use the IO​::* hierarchy much.

However\, here\, I'm trying to create an IO​::File-like object which will count how many bytes are written to the file\, and at some point\, when a threshold is exceeded\, close the file\, rename it\, and open a new one.

Naturally\, the code writing to that file does not have to know it behaves that way. And\, dynamically\, the handle could be one obtained through​:

  my $h = IO​::Handle->new;   sysopen($h\, ....);

I'm simply doing​:

  $fh->print(...)

and $fh is either my special object\, or an IO​::Handle. That's why I bothered using IO​::Handle at all!

I also don't understand the magic behind​:

  print $fh\, ...

If $fh is ANY object\, will it call "$fh->print" ?? But then\, I see in IO​::Handle​:

  sub print {   @​_ or croak 'usage​: $fh->print([ARGS])';   my $this = shift;   print $this @​_;   }

so clearly\, this cannot be\, or we would recurse infinitely. I deduce from that that there is some special handling in the Perl core for IO​::* objects?

If so\, is it an ->isa call\, or simply a check for the object under the IO​:: namesapce?

This is very\, very confusing\, and not properly documented.

Heck\, I'm the one who translated perlfaq5.pod in French! I'm supposed to know those things! Obviously\, I don't!

Raphael

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

print $fh\, ...   ^ strike the comma

If $fh is ANY object\, will it call "$fh->print" ??

Not at all.

If so\, is it an ->isa call\, or simply a check for the object under the IO​:: namesapce?

Better yet​: it doesn't work at all.

--tom

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

On Mar 1\, Raphael Manfredi said​:

sub print { @​_ or croak 'usage​: $fh->print([ARGS])'; my $this = shift; print $this @​_; }

so clearly\, this cannot be\, or we would recurse infinitely.

This is an implicit CORE​::print. I think the CORE​:: is implicit when doing​:

  sub some_perl_builtin {   # ...   some_perl_builtin()   }

but I could be very wrong.

-- MIDN 4/C PINYAN\, NROTCURPI\, US Naval Reserve japhy@​pobox.com http​://www.pobox.com/~japhy/ http​://pinyaj.stu.rpi.edu/ PerlMonth - An Online Perl Magazine http​://www.perlmonth.com/ The Perl Archive - Articles\, Forums\, etc. http​://www.perlarchive.com/

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Sounds like you should look into tied handles.

--tom

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

This is an implicit CORE​::print. I think the CORE​:: is implicit when doing​:

sub some_perl_builtin { # ... some_perl_builtin() }

but I could be very wrong.

I wouldn't say very\, but you are somewhat wrong\, sometimes. If you haven't imported it into this package to override the built-in\, then what you said is true.

But you can't always do this.

If toke.c's Perl_keyword() returns a negative number\, you can override it. If it doesn't\, you can't. And one class of things you can't usefully override is with those with optional dative slots. Some\, like print and printf\, enforce this; or rather\, your attempts to import them are tacitly ignored. Others\, like system\, do not mind but should\, because if you override them\, you change the syntax not just the semantics of the language and can no longer sneak an indirect object in.

--tom

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Quoting tchrist@​chthon.perl.com​: :Sounds like you should look into tied handles.

For only a PRINT\, this sounds like an overkill. BTW\, "my $h" does not work with current production Perl (5.005_03).

I think I'll stick to Symbol​::gensym() and do my own stuff. It's a pity though\, to have an IO​::* set of classes that don't work at all.

I'm not exactly a beginning Perl programmer. The mere fact that I have trouble using IO​::* classes the first time is worrying.

Raphael

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

I'm not exactly a beginning Perl programmer.

Hardly.

The mere fact that I have trouble using IO​::* classes the first time is worrying.

The most venerable Perl programmer(s) never even bother(s).

Here's all you need from the low-level IO.xs stuff\, the things that aren't in straight Perl (although some can be done\, but less conveniently)​:

  require IO​::Handle;   my @​IMPORTS;   BEGIN { @​IMPORTS = (qw/ blocking clearerr error formline getpos   setbuf setpos setvbuf sync untaint / ); }   use subs @​IMPORTS;

  for my $func (@​IMPORTS) {   no strict 'refs';   no warnings; # squelch wicked coercion of ($;$) in IO.xs's io_blocking()   *$func = \&{"IO​::Handle​::$func"};   }

  untaint(*STDIN);   formline(*STDERR\, "^" . ("\<" x 72) . "~~\n"\, "can this work " x 40);

Or\, if you like\, somewhat more robustly even than silly Mr I-can't-do-compile-time-checks Method calls​:

  require FileHandle;   {   no warnings; # next line predeclares w/ context coercer of (@​)

  use subs qw/ blocking clearerr error formline getpos setbuf setpos   setvbuf sync untaint /;

  sub clearerr(*) { shift->clearerr }   sub blocking(*\,$) { shift->blocking(@​_) }   sub error(*) { shift->error }   sub formline(*$@​) { shift->formline(@​_) }   sub getpos(*) { shift->getpos }   sub setbuf(*) { shift->setbuf(@​_) }   sub setpos(*$) { shift->setpos(@​_) }   sub setvbuf(*$$) { shift->setvbuf(@​_) }   sub sync(*) { shift->sync }   sub untaint(*) { shift->untaint }   }

  untaint(STDIN);   formline(STDERR\, "^" . ("\<" x 72) . "~~\n"\, "can this work " x 40);

(Yes\, I was too heavy-handed to look up the prototype redef warning class.)

That's not to say that IO​::Socket isn't nice to have. But this is usually all you need of it​:

  require IO​::Socket;   sub inet_socket { IO​::Socket​::INET->new(@​_) }

  *Mailer = inet_socket("localhost​:smtp");   print scalar \;

or

  my $mailer = inet_socket("localhost​:smtp");   print scalar \<$mailer>;

--tom

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

BTW\, "my $h" does not work with current production Perl (5.005_03). I think I'll stick to Symbol​::gensym() and do my own stuff.

Well\, you can use do { local *FH } instead\, but there used to be a leak there. There might even be one back then in gensym. Dunno.

--tom

p5pRT commented 19 years ago

From @smpeters

[manfredi@​lod28.gnb.st.com - Tue Feb 29 22​:04​:03 2000]​:

This is a bug report for perl from raphael.manfredi@​st.com\, generated with the help of perlbug 1.26 running under perl 5.00503.

----------------------------------------------------------------- I don't understand what's happening here​:

 1    use IO&#8203;::Handle;
 2    use File&#8203;::stat;
 3
 4    open\(STDERR\, ">bug\.stderr"\);
 5
 6    $fn = fileno\(\\\*main&#8203;::STDERR\);
 7    print "stderr at fd = \#$fn\\n";
 8
 9    $h = IO&#8203;::Handle\->new\_from\_fd\(\\\*main&#8203;::STDERR\, "w"\);
10    print $h "to stderr?\\n";
11    $h\->print\("to stderr again?\\n"\);
12
13    close STDERR;
14
15    my $st = stat\("bug\.stderr"\);
16    printf "size = %d\\n"\, $st\->size;
17
18    open\(FILE\, "bug\.stderr"\);
19    while \(\<FILE>\) \{
20        print;
21    \}
22

When run\, this produces​:

stderr at fd = \#2
size = 0

If I now "cat bug.stderr"\, I get​:

to stderr?
to stderr again?

which is correct.

It's not a File​::stat bug\, because if I move the test on line 15 before line 4\, I get the correct answer 28. -----------------------------------------------------------------

After a ticket with many comments not necessarily related to the problem\, the following program performs as expected.

#!/usr/bin/perl -w

use strict; use IO​::Handle; use File​::stat;

my $fh = \*STDERR; open($fh\, ">bug.stderr");

my $fn = fileno(\*main​::STDERR); print "stderr at fd = #$fn\n";

print $fh "to stderr?\n"; $fh->print("to stderr again?\n");

close STDERR;

my $st = stat("bug.stderr"); printf "size = %d\n"\, $st->size; print "About to read\n";

open(FILE\, "bug.stderr"); while (\) {   print;

p5pRT commented 19 years ago

@smpeters - Status changed from 'open' to 'resolved'