Perl / perl5

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

Interrelations of DESTROY and eval are not well documented #7768

Open p5pRT opened 19 years ago

p5pRT commented 19 years ago

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

Searchable as RT33940$

p5pRT commented 19 years ago

From porton@ex-code.com

Created by porton@ex-code.com

This is a bug report for perl from porton@​ex-code.com\, generated with the help of perlbug 1.35 running under perl v5.8.4.

----------------------------------------------------------------- I reasonably detailed scanned perlobj\, perltoot\, perlbot manpages\, read "die" and "eval" entries in perlfunc and found no answer.

The questions answer to which seems missing in Perl docs is​:

Consider code​:

eval {   my $obj1 = Class1->new;   {   my $obj2 = Class2->new;   # Suppose Class2->DESTROY calls 'die "2"'   }   # Suppose Class1->DESTROY also 'die "1"' }

What is now $@​?

I'd like if ($@​ eq "1") after this eval block (outer object to allow to override inner exception)\, but I found no warranty for ($@​ eq "1") in Perl docs.

Perl Info ``` Flags: category=docs severity=high Site configuration information for perl v5.8.4: Configured by Debian Project at Mon Oct 25 01:52:37 EST 2004. Summary of my perl5 (revision 5 version 8 subversion 4) configuration: Platform: osname=linux, osvers=2.4.27-ti1211, archname=i386-linux-thread-multi uname='linux kosh 2.4.27-ti1211 #1 sun sep 19 18:17:45 est 2004 i686 gnulinux ' config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=i386-linux -Dprefix=/usr -Dprivlib=/usr/share/perl/5.8 -Darchlib=/usr/lib/perl/5.8 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.8.4 -Dsitearch=/usr/local/lib/perl/5.8.4 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Uusesfio -Uusenm -Duseshrplib -Dlibperl=libperl.so.5.8.4 -Dd_dosuid -des' hint=recommended, useposix=true, d_sigaction=define usethreads=define use5005threads=undef useithreads=define usemultiplicity=define useperlio=define d_sfio=undef uselargefiles=define usesocks=undef use64bitint=undef use64bitall=undef uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64', optimize='-O2', cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -I/usr/local/include' ccversion='', gccversion='3.3.5 (Debian 1:3.3.5-1)', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 alignbytes=4, prototype=define Linker and Libraries: ld='cc', ldflags =' -L/usr/local/lib' libpth=/usr/local/lib /lib /usr/lib libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt perllibs=-ldl -lm -lpthread -lc -lcrypt libc=/lib/libc-2.3.2.so, so=so, useshrplib=true, libperl=libperl.so.5.8.4 gnulibc_version='2.3.2' Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E' cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib' Locally applied patches: @INC for perl v5.8.4: /usr/lib/perl5/5.005/i386-linux /etc/perl /usr/local/lib/perl/5.8.4 /usr/local/share/perl/5.8.4 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.8 /usr/share/perl/5.8 /usr/local/lib/site_perl . Environment for perl v5.8.4: HOME=/home/porton LANG (unset) LANGUAGE=en_US LC_COLLATE=ru_RU.KOI8-R LC_CTYPE=ru_RU.KOI8-R LC_MESSAGES=en_US LC_MONETARY=ru_RU.KOI8-R LC_NUMERIC=C LC_TIME=C LD_LIBRARY_PATH=/usr/local/lib LOGDIR (unset) PATH=~/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/sbin:/usr/sbin:/usr/local/sbin PERL5LIB=/usr/lib/perl5/5.005/i386-linux PERL_BADLANG (unset) SHELL=/bin/bash ```
p5pRT commented 19 years ago

From perl5-porters@ton.iguana.be

In article \rt\-3\.0\.11\-33940\-106489\.16\.0611746958661@​perl\.org\,   "Victor Porton\,\,\," (via RT) \perlbug\-followup@​perl\.org writes​:

I reasonably detailed scanned perlobj\, perltoot\, perlbot manpages\, read "die" and "eval" entries in perlfunc and found no answer.

The questions answer to which seems missing in Perl docs is​:

Consider code​:

eval { my $obj1 = Class1->new; { my $obj2 = Class2->new; # Suppose Class2->DESTROY calls 'die "2"' } # Suppose Class1->DESTROY also 'die "1"' }

What is now $@​?

I'd like if ($@​ eq "1") after this eval block (outer object to allow to override inner exception)\, but I found no warranty for ($@​ eq "1") in Perl docs.

Sorry\, it won't do what you want exactly.

dies in DESTROY append "\t(in cleanup)error message" to the existing $@​. It's documented in a rather obscure place\, in perlcall under G_KEEPERR\, and rather sideways even there. (you need to read rather carefully to infer it will happen for die in DESTROY) And it has some weird\, undocumented and broken trickery to try to avoid duplicate messages too.

I agree with you that it deserves a more highlevel explanation in a more visible place.

p5pRT commented 19 years ago

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

p5pRT commented 19 years ago

From ajs@ajs.com

On Wed\, 2005-01-26 at 15​:24\, Ton Hospel wrote​:

In article \rt\-3\.0\.11\-33940\-106489\.16\.0611746958661@​perl\.org\, "Victor Porton\,\,\," (via RT) \perlbug\-followup@​perl\.org writes​:

I reasonably detailed scanned perlobj\, perltoot\, perlbot manpages\, read "die" and "eval" entries in perlfunc and found no answer.

The questions answer to which seems missing in Perl docs is​:

Consider code​:

eval { my $obj1 = Class1->new; { my $obj2 = Class2->new; # Suppose Class2->DESTROY calls 'die "2"' } # Suppose Class1->DESTROY also 'die "1"' }

There are TONS of edge cases (and not so edge cases) around eval/die semantics. They'll all confuse you at first. The one that bit me hardest was actually fairly simple​:

  $start = time();   @​lines = eval {   $SIG{ALRM} = sub {die "timeout"};   alarm(2);   my $cmd = IO​::File->new("sleep 5|");   $cmd->getlines();   };   die $@​ if $@​ && ($@​ !~ /timeout/);   $end = time();   $delta = $end-$start;   print "Got "\,scalar(@​lines)\," answers in $delta seconds.\n";

Of course\, this fails (exits in the full 5 seconds) unless you move the declaration of $cmd outside of the eval so that destruction doesn't attempt to wait(2) on the child\, but that's very non-obvious to someone who is thinking in terms of "my signal handler said die\, so we jump outside of the eval."

I really wish at times that Perl had a safe eval that you could absolutely exit from.

-- ☎ 781-324-3772 ✉ ajs@​ajs.com ☷ http​://www.ajs.com/~ajs

p5pRT commented 19 years ago

From charles.e.derykus@boeing.com

The questions answer to which seems missing in Perl docs is​:

Consider code​:

eval { my $obj1 = Class1->new; { my $obj2 = Class2->new; # Suppose Class2->DESTROY calls 'die "2"' } # Suppose Class1->DESTROY also 'die "1"' }

There are TONS of edge cases (and not so edge cases) around eval/die semantics. They'll >>all confuse you at first. The one that bit me hardest was actually fairly simple​:

   $start = time\(\);
   @​lines = eval \{
      $SIG\{ALRM\} = sub \{die "timeout"\};
       alarm\(2\);
       my $cmd = IO​::File\->new\("sleep 5|"\);
       $cmd\->getlines\(\);
   \};
   die $@​ if $@​ && \($@​ \!~ /timeout/\);
   $end = time\(\);
   $delta = $end\-$start;
   print "Got "\,scalar\(@​lines\)\," answers in $delta seconds\.\\n";

Of course\, this fails (exits in the full 5 seconds) unless you move the declaration of $cmd outside of the eval so that destruction doesn't attempt to wait(2) on the child\, but >>that's very non-obvious to someone who is thinking in terms of "my signal handler said die\, so we jump outside of the eval."

If the child wait is the culprit\, I'm confused why this behaves differently​:

  # my $cmd = IO​::File->new("sleep 5|");   my $cmd = IO​::File->new("cat /dev/zero|");

The 2 second timeout works as expected now; whereas\, the potentially dueling duo (alarm/sleep) in your example seem risky...

-- Charles DeRykus

p5pRT commented 13 years ago

From @cpansprout

This is now documented in perl5140delta\, but it still needs to be documented clearly elsewhere.

p5pRT commented 11 years ago

From @jkeenan

On Sat Apr 30 22​:49​:35 2011\, sprout wrote​:

This is now documented in perl5140delta\, but it still needs to be documented clearly elsewhere.

Is this the section of perl5140delta you were referring to?

########## Stack unwinding

The protocol for unwinding the C stack at the last stage of a die has changed how it identifies the target stack frame. This now uses a separate variable PL_restartjmpenv \, where previously it relied on the blk_eval.cur_top_env pointer in the eval context frame that has nominally just been discarded. This change means that code running during various stages of Perl-level unwinding no longer needs to take care to avoid destroying the ghost frame. ##########

(I ask because this RT number is not explicitly referenced in that document.)

Where else should this documentation go (so that we can close the ticket)?

Thank you very much. Jim Keenan

p5pRT commented 11 years ago

From zefram@fysh.org

James E Keenan via RT wrote​:

Where else should this documentation go (so that we can close the ticket)?

It should be described in perlguts.

-zefram