DESTROY gotcha

Discussion in 'Perl Misc' started by Rainer Weikusat, Jan 1, 2013.

  1. As far as I could determine, this isn't documented anywhere, hence, I
    thought I should post it: Perl exceptions, including automatically
    generated ones caused by attempts to call a non-existant subroutine or
    invoke a method using undef as invocant, are not propagated out of
    Perl object destructors, ie, the following code

    -------------
    package Boo;

    sub new
    {
    return bless([], $_[0]);
    }

    sub DESTROY
    {
    $_[2]->the_end_of_the_world_lost();
    }

    package main;

    my $o = Boo->new();
    $o = undef;

    print("So we had to continue ...\n");
    ------------

    will print 'So we had to continue ...' (this caused me quite some head
    scratching yesterday because 'some code' on an appliance in Korea
    apparently managed to 'escape' from a certain scope without executing
    all of the contained code).
    Rainer Weikusat, Jan 1, 2013
    #1
    1. Advertising

  2. Rainer Weikusat

    C.DeRykus Guest

    On Tuesday, January 1, 2013 9:56:47 AM UTC-8, Rainer Weikusat wrote:
    > As far as I could determine, this isn't documented anywhere, hence, I
    >
    > thought I should post it: Perl exceptions, including automatically
    >
    > generated ones caused by attempts to call a non-existant subroutine or
    >
    > invoke a method using undef as invocant, are not propagated out of
    >
    > Perl object destructors, ie, the following code
    >
    >
    >
    > -------------
    >
    > package Boo;
    >
    >
    >
    > sub new
    >
    > {
    >
    > return bless([], $_[0]);
    >
    > }
    >
    >
    >
    > sub DESTROY
    >
    > {
    >
    > $_[2]->the_end_of_the_world_lost();
    >
    > }
    >
    >
    >
    > package main;
    >
    >
    >
    > my $o = Boo->new();
    >
    > $o = undef;
    >
    >
    >
    > print("So we had to continue ...\n");
    >
    > ------------
    >
    >
    >
    > will print 'So we had to continue ...' (this caused me quite some head
    >
    > scratching yesterday because 'some code' on an appliance in Korea
    >
    > apparently managed to 'escape' from a certain scope without executing
    >
    > all of the contained code).


    Perl special cases exceptions in DESTROY and so they're
    untrappable. With -w though you'll at least see:

    (in cleanup) Can't call method "the_end_of_the_world_lost"
    on an undefined value at ...

    Here's some background on the problem (and controversy):
    http://www.perlmonks.org/index.pl?node_id=924488

    --
    Charles DeRykus
    C.DeRykus, Jan 2, 2013
    #2
    1. Advertising

  3. "C.DeRykus" <> writes:
    >> As far as I could determine, this isn't documented anywhere, hence,

    [...]

    >> -------------
    >>
    >> package Boo;
    >>
    >>
    >>
    >> sub new
    >>
    >> {
    >>
    >> return bless([], $_[0]);
    >>
    >> }
    >>
    >>
    >>
    >> sub DESTROY
    >>
    >> {
    >>
    >> $_[2]->the_end_of_the_world_lost();
    >>
    >> }
    >>
    >>
    >>
    >> package main;
    >>
    >>
    >>
    >> my $o = Boo->new();
    >>
    >> $o = undef;
    >>
    >>
    >>
    >> print("So we had to continue ...\n");
    >>
    >> ------------
    >> will print 'So we had to continue ...' (this caused me quite some head


    [...]

    > Perl special cases exceptions in DESTROY and so they're
    > untrappable. With -w though you'll at least see:
    >
    > (in cleanup) Can't call method "the_end_of_the_world_lost"
    > on an undefined value at ...
    >
    > Here's some background on the problem (and controversy):
    > http://www.perlmonks.org/index.pl?node_id=924488


    That's actually about a somewhat different issue, namely, 'user
    exceptions' in destructors, not about fatal execution errors perl
    can only detect at runtime (and the behaviour I observed occurred on
    5.10.1). And the main issue here is really that the 'in cleanup'
    explanation is the only documentation about this I'm presently aware
    of[*].

    [*] Considering that this isn't documented, it is - by definition - a
    bug :->.
    Rainer Weikusat, Jan 2, 2013
    #3
  4. Rainer Weikusat

    C.DeRykus Guest

    On Wednesday, January 2, 2013 4:08:18 AM UTC-8, Rainer Weikusat wrote:
    > "C.DeRykus" <> writes:
    >
    > >> As far as I could determine, this isn't documented anywhere, hence,

    >
    > [...]
    >
    >
    >
    > >> -------------

    >
    > >>

    >
    > >> package Boo;

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> sub new

    >
    > >>

    >
    > >> {

    >
    > >>

    >
    > >> return bless([], $_[0]);

    >
    > >>

    >
    > >> }

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> sub DESTROY

    >
    > >>

    >
    > >> {

    >
    > >>

    >
    > >> $_[2]->the_end_of_the_world_lost();

    >
    > >>

    >
    > >> }

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> package main;

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> my $o = Boo->new();

    >
    > >>

    >
    > >> $o = undef;

    >
    > >>

    >
    > >>

    >
    > >>

    >
    > >> print("So we had to continue ...\n");

    >
    > >>

    >
    > >> ------------

    >
    > >> will print 'So we had to continue ...' (this caused me quite some head

    >
    >
    >
    > [...]
    >
    >
    >
    > > Perl special cases exceptions in DESTROY and so they're

    >
    > > untrappable. With -w though you'll at least see:

    >
    > >

    >
    > > (in cleanup) Can't call method "the_end_of_the_world_lost"

    >
    > > on an undefined value at ...

    >
    > >

    >
    > > Here's some background on the problem (and controversy):

    >
    > > http://www.perlmonks.org/index.pl?node_id=924488

    >
    >
    >
    > That's actually about a somewhat different issue, namely, 'user
    >
    > exceptions' in destructors, not about fatal execution errors perl
    >
    > can only detect at runtime (and the behaviour I observed occurred on
    >
    > 5.10.1). And the main issue here is really that the 'in cleanup'


    Hm, the discussion didn't touch on it but perl's
    handling of any destructor fatality is the same
    eg,

    (in cleanup) Illegal division by zero ...

    There's at least more explanation in perldiag:

    (in cleanup) %s
    (W misc) This prefix usually indicates that a
    DESTROY() method raised the indicated exception.
    ...


    >
    > explanation is the only documentation about this I'm presently aware
    >
    > of[*].
    >
    >
    >
    > [*] Considering that this isn't documented, it is - by definition - a
    >
    > bug :->.


    At least a nasty, poorly documented feature...

    --
    Charles DeRykus
    C.DeRykus, Jan 2, 2013
    #4
  5. Ben Morrow <> writes:
    > Quoth "C.DeRykus" <>:
    >>
    >> Hm, the discussion didn't touch on it but perl's
    >> handling of any destructor fatality is the same
    >> eg,
    >>
    >> (in cleanup) Illegal division by zero ...
    >>
    >> There's at least more explanation in perldiag:
    >>
    >> (in cleanup) %s
    >> (W misc) This prefix usually indicates that a
    >> DESTROY() method raised the indicated exception.
    >> ...

    > <snip>
    >>
    >> At least a nasty, poorly documented feature...

    >
    > As of 5.16 this is documented in perlobj,


    Not really (except if the behaviour was changed). The corresponding
    text is "If your DESTROY method throws an error, this error will be
    ignored." But this is not just about application code running from a
    destructor invoking die but about any (AFAIK) otherwise fatal runtime
    error occurring while running a DESTROY method.

    In my case, this was some 'database serialization' code whose
    execution was triggered when an object was removed from this database
    after the last reference to it went away when the referencing object
    was destroyed[*]. This basically uses Data::Dumper to write the
    contents of an anonymous array of objects to a text file. Afterwards,
    to counteract anything which might have been done when 'freezing' the
    objects, Data::Dumper::Freezer) a 'thaw' method is invoked for all
    objects in the anonymous array. Because of an error in some other
    code, one of the array elements wasn't an object but undef. The "Can't
    call ... on an undefined value" error caused by that was ignored. Some
    time later, a new object was added to this database, triggering
    another serialization, this time not from 'a cleanup context'. Hence,
    the attempt to invoke ->thaw using the undef value introduced earlier
    aborted now (this was a part of the events which occured prior to this
    program going into a crash - restart - crash - restart loop I had to
    infer from the available diagnostic output after the 'visible problem'
    was noticed and the corrupted on-disk database removed).

    [*] Yes, I'm really doing 'application reference counting' for objects
    on top of the perl garbage collection mechanism.
    Rainer Weikusat, Jan 3, 2013
    #5
  6. Rainer Weikusat

    C.DeRykus Guest

    On Thursday, January 3, 2013 5:44:26 AM UTC-8, Rainer Weikusat wrote:
    > Ben Morrow <> writes:
    >
    > > Quoth "C.DeRykus" <>:

    >
    > >>

    >
    > >> Hm, the discussion didn't touch on it but perl's

    >
    > >> handling of any destructor fatality is the same

    >
    > >> eg,

    >
    > >>

    >
    > >> (in cleanup) Illegal division by zero ...

    >
    > >>

    >
    > >> There's at least more explanation in perldiag:

    >
    > >>

    >
    > >> (in cleanup) %s

    >
    > >> (W misc) This prefix usually indicates that a

    >
    > >> DESTROY() method raised the indicated exception.

    >
    > >> ...

    >
    > > <snip>

    >
    > >>

    >
    > >> At least a nasty, poorly documented feature...

    >
    > >

    >
    > > As of 5.16 this is documented in perlobj,

    >
    >
    >
    > Not really (except if the behaviour was changed). The corresponding
    >
    > text is "If your DESTROY method throws an error, this error will be
    >
    > ignored." But this is not just about application code running from a
    >
    > destructor invoking die but about any (AFAIK) otherwise fatal runtime
    >
    > error occurring while running a DESTROY method.
    >
    >


    Hm, maybe eval and exit on error as a safeguard..?

    sub DESTROY
    {
    return if ${^GLOBAL_PHASE} eq 'DESTRUCT';

    eval {
    ...
    $_[2]->the_end_of_the_world_lost();
    ...

    };
    print "fatal error in DESTROY: $@" and exit 1 if $@;
    }

    ....

    --
    Charles DeRykus
    C.DeRykus, Jan 4, 2013
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roedy Green

    ZipFile.entries gotcha

    Roedy Green, Sep 26, 2003, in forum: Java
    Replies:
    9
    Views:
    616
    Phil...
    Sep 29, 2003
  2. VisionSet

    JCert & JLS gotcha

    VisionSet, Oct 6, 2003, in forum: Java
    Replies:
    0
    Views:
    348
    VisionSet
    Oct 6, 2003
  3. gbruno

    apache tomcat Gotcha

    gbruno, Apr 27, 2005, in forum: Java
    Replies:
    2
    Views:
    674
    Bryce
    Apr 27, 2005
  4. Tony Morris

    another enum gotcha

    Tony Morris, Jan 14, 2006, in forum: Java
    Replies:
    2
    Views:
    402
    Thomas Hawtin
    Jan 14, 2006
  5. Ook
    Replies:
    2
    Views:
    323
Loading...

Share This Page