flipper has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks

I'm having a problem with a large object-based system which results in perl SEGVing. I've reduced it to a small case, which involves calling the contructor of a singleton-type object during global destruction.

I'm aware that it's not a particularly nice thing to do, but I don't think crashing is an appropriate response from perl!

*Edited to remove weaken(), as it is not related to the issue*

The following file is Foo.pm:

package Foo; use strict; use XML::LibXML; use Scalar::Util qw/weaken/; sub DESTROY { my $self=shift; warn "\n\n$self dtor"; } sub new() { warn "\n\n".__PACKAGE__." xtor"; my $self = {}; bless $self, __PACKAGE__; my $parser = new XML::LibXML(); my $confdoc = $parser->parse_string('<foo att1="val1"/>'); my $root = $confdoc->documentElement(); my @nodes = $root->findnodes('/*'); for my $n (@nodes){ for my $att ($n->attributes()) { my $foo = $att->nodeName; warn "foo $foo"; warn "lctest: ".lc("LOWERCASEME!"); warn "lcfoo ".lc($foo); my ($key, $val) = (lc($att->nodeName), lc($att +->getValue)); warn "$key - $val"; } } warn "\n".__PACKAGE__."xtor COMPLETE"; return $self; } 1;

If I then instantiate the object from a destructor it crashes, but only if I created one earlier!?

geedorah:~/perldtorbug# perl -MFoo -e 'package foo; bless ($self=[]) = +> __PACKAGE__; sub DESTROY {Foo->new()}' Foo xtor at Foo.pm line 12 during global destruction. foo att1 at Foo.pm line 22 during global destruction. lctest: lowercaseme! at Foo.pm line 23 during global destruction. lcfoo att1 at Foo.pm line 24 during global destruction. att1 - val1 at Foo.pm line 26 during global destruction. Fooxtor COMPLETE at Foo.pm line 29 during global destruction. Foo=HASH(0x81cea10) dtor at Foo.pm line 8 during global destruction. geedorah:~/perldtorbug# perl -MFoo -e 'package foo; bless ($self=[]) = +> __PACKAGE__;$f=Foo->new(); sub DESTROY {Foo->new()}' Foo xtor at Foo.pm line 12. foo att1 at Foo.pm line 22. lctest: lowercaseme! at Foo.pm line 23. lcfoo att1 at Foo.pm line 24. att1 - val1 at Foo.pm line 26. Fooxtor COMPLETE at Foo.pm line 29. Foo=HASH(0x817fa00) dtor at Foo.pm line 8 during global destruction. Foo xtor at Foo.pm line 12 during global destruction. foo att1 at Foo.pm line 22 during global destruction. lctest: lowercaseme! at Foo.pm line 23 during global destruction. Segmentation fault geedorah:~/perldtorbug# dmesg |tail -1 [1797167.620092] perl[9540]: segfault at 0 ip 081178d3 sp bfffdd90 err +or 4 in perl[8048000+131000] geedorah:~/perldtorbug# perl -v This is perl, v5.10.0 built for i486-linux-gnu-thread-multi Copyright 1987-2007, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5 source ki +t. Complete documentation for Perl, including FAQ lists, should be found +on this system using "man perl" or "perldoc perl". If you have access to + the Internet, point your browser at http://www.perl.org/, the Perl Home Pa +ge. geedorah:~/perldtorbug#

Should I perlbug it?

thanks


peter

Replies are listed 'Best First'.
Re: perl crash during global destruction
by GrandFather (Saint) on Mar 31, 2010 at 19:45 UTC

    Your test case can be simplified somewhat further and still crash:

    #!/usr/bin/perl use strict; use warnings; package Foo; sub new { my ($class) = @_; return bless {}, $class; } sub DESTROY { Foo->new(); } package main; Foo->new ();

    It may even be obvious now why it crashes. No? Well, consider what happens to the instance constructed in the destructor as the destructor cleans up before exiting.

    It may be that this is a different issue than the one you are experiencing (I can't tell exactly from your various snippets of code), but it is the problem you describe.

    Actually there are a number of issues in your code that look a little Perl 4ish or otherwise sub-optimum.

    • Don't use prototypes unless you really understand what they do. I can't think of any good use of a prototype for a constructor.
    • Use the XML::LibXML->new () syntax for call constructors.
    • bless $self, __PACKAGE__ makes inheritance tricky. Instead use:
      sub new { my ($class) = @_; my $self = bless {}, $class; ...
    • Oh, and don't construct instances of a class in the class's destructor - that leads to unhappiness.

    True laziness is hard work

      Yes I don't think the code I gave was very easy to understand - too many foos!

      The style issues were mostly introduced by me paring down 20,000 lines of code to 40 (and the odd C++ programmer :)

      Your example is not exactly the same as the issue I'm seeing, but your example is much clearer - based on that, the following does not crash:

      package Foo; use strict; use XML::LibXML; use Scalar::Util qw/weaken/; use Data::Dumper; sub DESTROY { my $self=shift; warn "\n$self dtor"; } sub new { warn "\n".__PACKAGE__." xtor"; my $self = {}; bless $self, __PACKAGE__; my $parser = XML::LibXML->new(); my $confdoc = $parser->parse_string('<foo att1="val1"/>'); my $root = $confdoc->documentElement(); my @nodes = $root->findnodes('/*'); for my $n (@nodes){ for my $att ($n->attributes()) { my $foo = $att->nodeName; my ($key, $val) = (lc($att->nodeName), lc($att +->getValue)); warn "$key - $val"; } } warn __PACKAGE__." xtor COMPLETE"; return $self; } package user; sub DESTROY {Foo->new()} bless my $self=[] => __PACKAGE__; my $f=Foo->new();

      but essentially the same code using a Foo.pm and crash.pl does:

      #Foo.pm package Foo; use strict; use XML::LibXML; use Scalar::Util qw/weaken/; use Data::Dumper; sub DESTROY { my $self=shift; warn "\n$self dtor"; } sub new { warn "\n".__PACKAGE__." xtor"; my $self = {}; bless $self, __PACKAGE__; my $parser = XML::LibXML->new(); my $confdoc = $parser->parse_string('<foo att1="val1"/>'); my $root = $confdoc->documentElement(); my @nodes = $root->findnodes('/*'); for my $n (@nodes){ for my $att ($n->attributes()) { my $foo = $att->nodeName; my ($key, $val) = (lc($att->nodeName), lc($att +->getValue)); warn "$key - $val"; } } warn __PACKAGE__." xtor COMPLETE"; return $self; } 1;
      #!/usr/bin/perl #this is crash.pl use Foo; package user; bless ($self=[]) => __PACKAGE__; $f=Foo->new(); sub DESTROY {Foo->new()}
        The code is essentially different. If you insert the two my's missing in crash.pl, you will get the same results.

      Oh, and don't construct instances of a class in the class's destructor - that leads to unhappiness.
      He did not do that, did he?

      Cheers, Christoph
        Oh, and don't construct instances of a class in the class's destructor
        He did not do that, did he?

        In the crash case OP presented that is exactly what he did:

        package foo; ... $f=Foo->new(); sub DESTROY {Foo->new()}

        supplies a Foo destructor that creates a new Foo instance. Note that the new destructor replaces the original destructor. It would have been clearer (and the OP may have figured things out for himself) if OP had supplied a stand alone sample script that demonstrated the issue.


        True laziness is hard work