Perl: the Markov chain saw PerlMonks

### Perl segfault and global destruction problem

by Hofmator (Curate)
 on Jan 09, 2004 at 10:49 UTC Need Help??
Hofmator has asked for the wisdom of the Perl Monks concerning the following question:

This is a follow-up on djantzen's post Depth First Search through Digraph Results in Memory Leak.

I played around and simplified the program as far as possible, ending up at the following:

```use strict;
use warnings;

sub UNIVERSAL::DESTROY
{
warn "DESTROYING @_\n";
}

sub dfs
{
my (\$node, \$sub) = @_;
my %visited;

my \$dfs;
\$dfs = sub {
my (\$n) = @_;
\$visited{\$n}++;
\$sub->(\$n);
for (@\$n) {
next unless ref;
\$dfs->(\$_->[0]) unless \$visited{\$_->[0]};
}
};

\$dfs->(\$node);
}

sub do_dfs
{
my (\$node) = @_;
my \$nodes = [];
my \$search = sub { push @\$nodes, \$_[0] };
dfs(\$node,\$search);

# UNCOMMENT NEXT LINE to see bug
#  return \$nodes;

my @nodes = @\$nodes;
undef \$nodes;
return [@nodes];
}

warn "STARTING\n";

{
my \$node1 = bless [1], "Node";
my \$node2 = bless [2], "Node";

{
my \$nodes = do_dfs(\$node1);
warn "Neighbors\n";
warn "  \$_\n" for (@\$nodes);
}
}

warn "SHOULD BE THE LAST THING PRINTED.\n";

This gives the following expected output:

```STARTING
Neighbors
Node=ARRAY(0x8148a8c)
Node=ARRAY(0x8148b94)
DESTROYING Node=ARRAY(0x8148a8c) at segfault.pl line 6.
DESTROYING Link=ARRAY(0x818fc00) at segfault.pl line 6.
DESTROYING Node=ARRAY(0x8148b94) at segfault.pl line 6.
SHOULD BE THE LAST THING PRINTED.

However, uncommenting the indicated line, leads to the follwing output and a segfault.

```STARTING
Neighbors
Node=ARRAY(0x8148a8c)
Node=ARRAY(0x8148b94)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x8148a8c) at segfault.pl line 6 during global d
+estruction.
DESTROYING Link=ARRAY(0x818fc48) at segfault.pl line 6 during global d
+estruction.
DESTROYING Node=ARRAY(0x8148b94) at segfault.pl line 6 during global d
+estruction.
DESTROYING IO::Handle=IO(0x818fc6c) at segfault.pl line 6 during globa
+l destruction.
DESTROYING IO::Handle=IO(0x815c018) at segfault.pl line 6 during globa
+l destruction.

• Why is the order of destruction changed?
• Where do the two IO::Handles come from?
• Why the segfault?

I'm on Linux running perl 5.8.0. Can someone confirm with other versions of perl?

Update
OK, summing up the results other people got, the follwoing perls segfault

• 5.6.1
• 5.8.0
and these perls do not segfault:
• 5.005_03
• 5.6.0
• 5.6.1d
• 5.6.2
• 5.8.1
• 5.8.2
• 5.8.3-RC1

What is still consistenly wrong is destruction order. The objects referenced in \$node1 and \$node2 should be destroyed on block exit not during global destruction, shouldn't they?

-- Hofmator

Replies are listed 'Best First'.
Re: Perl segfault and global destruction problem
by borisz (Canon) on Jan 09, 2004 at 11:11 UTC
With perl 5.8.1 no segfaults.
```STARTING
Neighbors
Node=ARRAY(0x8151be0)
Node=ARRAY(0x8151cf4)
DESTROYING Node=ARRAY(0x8151be0)
DESTROYING Node=ARRAY(0x8151cf4)
SHOULD BE THE LAST THING PRINTED.

STARTING
Neighbors
Node=ARRAY(0x8151be0)
Node=ARRAY(0x8151cf4)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x8151cf4)
DESTROYING Node=ARRAY(0x8151be0)
DESTROYING IO::Handle=IO(0x819cf50)
DESTROYING IO::Handle=IO(0x8167af0)
DESTROYING IO::Handle=IO(0x8167b5c)
DESTROYING IO::Handle=IO(0x8165a6c)
Boris
Re: Perl segfault and global destruction problem
by PodMaster (Abbot) on Jan 09, 2004 at 11:14 UTC
Except when I note there is no segfault, there is a segfault. All these are activeperl flavored perls (d stands for debug version).
```E:\>perl C:\dev\loose\perl.segfault.320069.pl
STARTING
Neighbors
Node=ARRAY(0x1abf0f8)
Node=ARRAY(0x1abf1b8)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x1abf0f8)
DESTROYING Node=ARRAY(0x1abf1b8)

E:\>G:\perl\bin\perl C:\dev\loose\perl.segfault.320069.pl
STARTING
Neighbors
Node=ARRAY(0x15d5014)
Node=ARRAY(0x15d50d4)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x15d50d4)
DESTROYING Node=ARRAY(0x15d5014)
DESTROYING IO::Handle=IO(0x1a41d80)

E:\>G:\perls\5.6.0\bin\perl C:\dev\loose\perl.segfault.320069.pl
STARTING
Neighbors
Node=ARRAY(0x85d24f0)
Node=ARRAY(0x85d258c)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x85d24f0)
DESTROYING Node=ARRAY(0x85d258c)
DESTROYING IO::Handle=IO(0x85df564)
DESTROYING IO::Handle=IO(0x85dca54)
DESTROYING IO::Handle=IO(0x85dcb14)

E:\>echo NO SEGFAULT on 5.6.0
NO SEGFAULT on 5.6.0

E:\>G:\perls\5.6.1\bin\perl C:\dev\loose\perl.segfault.320069.pl
STARTING
Neighbors
Node=ARRAY(0x1abf0f8)
Node=ARRAY(0x1abf1b8)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x1abf0f8)
DESTROYING Node=ARRAY(0x1abf1b8)

E:\>G:\perls\5.6.2\bin\perl C:\dev\loose\perl.segfault.320069.pl
STARTING
Neighbors
Node=ARRAY(0x1a7f0f8)
Node=ARRAY(0x1a7f1b8)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x1a7f0f8)
DESTROYING Node=ARRAY(0x1a7f1b8)
DESTROYING IO::Handle=IO(0x1a752c8)
DESTROYING IO::Handle=IO(0x1a77d34)
DESTROYING IO::Handle=IO(0x1a7522c)

E:\>echo NO SEGFAULT ON 5.6.2 either
NO SEGFAULT ON 5.6.2 either

E:\>G:\perls\5.8.1\bin\perl C:\dev\loose\perl.segfault.320069.pl
STARTING
Neighbors
Node=ARRAY(0x15d5050)
Node=ARRAY(0x15d5110)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x15d5050)
DESTROYING Node=ARRAY(0x15d5110)
DESTROYING IO::Handle=IO(0x1a41eb4)
DESTROYING IO::Handle=IO(0x1a41f74)
DESTROYING IO::Handle=IO(0x1a41fe0)

E:\>echo no segfault
no segfault

E:\>G:\perls\5.8.2\bin\perl C:\dev\loose\perl.segfault.320069.pl
STARTING
Neighbors
Node=ARRAY(0x15d5060)
Node=ARRAY(0x15d5120)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x15d5060)
DESTROYING Node=ARRAY(0x15d5120)
DESTROYING IO::Handle=IO(0x1a44ff4)
DESTROYING IO::Handle=IO(0x1a41f1c)
DESTROYING IO::Handle=IO(0x1a41fdc)

E:\>echo no_segfault
no_segfault

E:\>
E:\>G:\perls\5.005_03\bin\perl C:\dev\loose\perl.segfault.320069.pl
STARTING
Neighbors
Node=ARRAY(0x365820)
Node=ARRAY(0x365844)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x365820)
DESTROYING Node=ARRAY(0x365844)
DESTROYING IO::Handle=IO(0x36f6dc)
DESTROYING IO::Handle=IO(0x36c8ec)
DESTROYING IO::Handle=IO(0x36c9ac)

E:\>echo nosegfault
nosegfault
E:\>G:\perls\5.6.1d\bin\perl C:\dev\loose\perl.segfault.320069.pl
STARTING
Neighbors
Node=ARRAY(0x1a7f118)
Node=ARRAY(0x1a7f1d8)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x1a7f118)
DESTROYING Node=ARRAY(0x1a7f1d8)
DESTROYING IO::Handle=IO(0x1a752e8)
DESTROYING IO::Handle=IO(0x1a77d54)
DESTROYING IO::Handle=IO(0x1a7524c)

E:\>echo nosegfault
nosegfault

 MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!" I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README). ** The third rule of perl club is a statement of fact: pod is sexy.

Re: Perl segfault and global destruction problem
by liz (Monsignor) on Jan 09, 2004 at 11:12 UTC
Why the segfault?

I can't answer that. What I can see is that this does not segfault in 5.8.1, 5.8.2 and 5.8.3-RC1. So I guess this was fixed in 5.8.1.

Hope this helps.

Liz

Re: Perl segfault and global destruction problem
by maa (Pilgrim) on Jan 09, 2004 at 11:16 UTC

Confirmed:

ActiveState Perl 5.6.1 on Win NT4 SP6a...

```STARTING
Neighbors
Node=ARRAY(0x1b9ee88)
Node=ARRAY(0x1b9ef48)
SHOULD BE THE LAST THING PRINTED.
DESTROYING Node=ARRAY(0x1b9ee88)
DESTROYING Node=ARRAY(0x1b9ef48)
```
Crashed with...
The instruction at "0x28071ad3" referenced memory at <blah> whcih could not be read.
which is what happens when you write a program that uses a pointer wrongly in C...

hash order
by Anonymous Monk on Jan 09, 2004 at 15:49 UTC
If I'm not mistaken, those objects are stored internally by a hash table, so any tweaks to this would change the order in which they are destroyed. If you don't explicitly blow them away (and you don't) then you're subject to the joys of whatever order they are in when they come out of the hash.

Your problem is that your subnodes are destroyed before the parent node, but the parent still has a link to them. When the parent goes away, the ref count for the subnodes drops to 0 and then they get destroyed. But since they've already been destroyed, there is a problem.

Putting these two together the solution is to walk your tree, and delete the links between the nodes. That breaks the interdependancies and should get you on your way.

Or haven't had enough caffeine yet, in which case you're on your own.

- doug

PS: I have no idea what those IO::Handles are doing there.

Create A New User
Node Status?
node history
Node Type: perlquestion [id://320069]
Approved by broquaint
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (6)
As of 2018-05-20 10:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
World peace can best be achieved by:

Results (150 votes). Check out past polls.

Notices?