develooper Front page | perl.perl5.porters | Postings from September 2010

Nondeterministic (and possibly incorrect) destructor order

Thread Next
From:
Ed Avis
Date:
September 13, 2010 08:20
Subject:
Nondeterministic (and possibly incorrect) destructor order
Message ID:
loom.20100913T170854-144@post.gmane.org
Hi, rather than file this as a bug I thought I'd discuss it here,
since it may be my assumptions which are at fault.  I have a program
that uses AUTOLOAD to delegate method calls.  Among other things this
catches the DESTROY call at program exit.  But by the time DESTROY is
called, I find that my object has been hollowed out and the value I
wanted to use is undef - presumably it has been destroyed already - so
I get uninitialized value errors during global destruction.

Before I give the test program below, I'd like to note firstly that I
realize the original code it came from was buggy.  I don't in fact
want to do anything special for DESTROY operations and so my AUTOLOAD
sub could just return in this case.  Secondly, even a minor change to
the code - such as removing the seemingly do-nothing 'for ($port) {}'
- causes the error not to happen.  The order in which destruction
happens (or whatever else is the cause) seems to depend on perl's
memory layout or other coincidences.  That is partly what motivates me
to make this report, since surely destruction should happen in a
predictable order, or at least promising that an object's DESTROY is
called _before_ destroying the other things it references.

My system is the stock perl-5.10.0 from Fedora 12 on x86_64.  I hope
at least some people will be able to reproduce the message on their
systems.

use 5.010;
use warnings;
$| = 1;
use SOAP::Lite;
package A;
use HTML::Entities;
our $AUTOLOAD;
sub new {
    my $class = shift;
    my ($host, $port, $path, $bogus_uri) = @_;
    my $soap_obj = SOAP::Lite->on_action(sub{});
    say 'made ', ref $soap_obj;
    return bless \$soap_obj, $class;
}
sub call {
    my ($self, $method, @args) = @_;
    my $soap_obj = $$self;
    say "method $method on '", ($soap_obj // ''), "'";
    my $r = $soap_obj->$method();
}
sub AUTOLOAD {
    my $self = shift;
    my $method = $AUTOLOAD;
    $method =~ s/\AA::// or die;
    return $self->call($method);
}
package B;
my %known_ports = ();
my %existing;
my $port;
sub new {
    my ($class, $x, $y) = @_;
    for ($port) {}
    for ($existing{$x}) {
        my $soap_obj = new A
            'IJobServer';
        $_ = bless \$soap_obj, $class;
        return $_;
    }
}
my $c = new B 1, 2;


When I run this it prints:

made SOAP::Lite
method DESTROY on ''
       (in cleanup) Can't call method "DESTROY" on an undefined value at ./jt1\
 line 19 during global destruction.

I did not expect "method DESTROY on ''".  Surely the inner SOAP::Lite
object, referenced by my A object, should still be around and not set
to undef.

Is this a reasonable assumption?  (If not, perhaps it would be better
for perl to guarantee that the inner object is *always* destroyed
first or at least the reference is always set to undef, so at least
it'd be predictable.)

-- 
Ed Avis <eda@waniasset.com>


Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About