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

Interrelations of DESTROY and eval are not well documented #7768

Open
p5pRT opened this issue Jan 26, 2005 · 8 comments
Open

Interrelations of DESTROY and eval are not well documented #7768

p5pRT opened this issue Jan 26, 2005 · 8 comments

Comments

@p5pRT
Copy link

p5pRT commented Jan 26, 2005

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

Searchable as RT33940$

@p5pRT
Copy link
Author

p5pRT commented Jan 26, 2005

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
Copy link
Author

p5pRT commented Jan 26, 2005

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
Copy link
Author

p5pRT commented Jan 26, 2005

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

@p5pRT
Copy link
Author

p5pRT commented Jan 26, 2005

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
Copy link
Author

p5pRT commented Jan 26, 2005

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\(\);
   @&#8203;lines = eval \{
      $SIG\{ALRM\} = sub \{die "timeout"\};
       alarm\(2\);
       my $cmd = IO&#8203;::File\->new\("sleep 5|"\);
       $cmd\->getlines\(\);
   \};
   die $@&#8203; if $@&#8203; && \($@&#8203; \!~ /timeout/\);
   $end = time\(\);
   $delta = $end\-$start;
   print "Got "\,scalar\(@&#8203;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
Copy link
Author

p5pRT commented May 1, 2011

From @cpansprout

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

@p5pRT
Copy link
Author

p5pRT commented Feb 16, 2013

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
Copy link
Author

p5pRT commented Aug 29, 2013

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants