Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the autobox CPAN distribution.

Report information
The Basics
Id: 71777
Status: resolved
Priority: 0/
Queue: autobox

People
Owner: CHOCOLATE [...] cpan.org
Requestors: bobtfish [...] bobtfish.net
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 2.75
Fixed in: (no value)



Subject: Having autobox loaded makes method calls on already destoryed objects segfault in global destruction
I have extracted a standalone test case from my work code which was causing the failure: use strict; use warnings; use Test::More; is system('/usr/bin/perl', '-e', q{{ package Foo; use Moose::Autobox; sub get_bar { $_[0]->{bar} } sub foo {} sub DESTROY { $_->[0]->get_bar->bar } } { package Bar; use Moose::Autobox; sub get_foo { $_->[0]->{foo} } sub bar {} sub DESTROY { $_->[0]->get_foo->foo } } my $foo = bless {}, 'Foo'; my $bar = bless { foo => $foo }, 'Bar'; $foo->{bar} = $bar; exit(0); }), 0; done_testing; The above fails (as the script segfaults), however it works perfectly without the Moose::Autobox being added (but not used anywhere). This fails for me on both i386 linux and i386 darwin. Backtrace from this happening in 'real' code: Program received signal SIGSEGV, Segmentation fault. 0x00007ffff4951d97 in ?? () from /usr/lib/perl5/auto/autobox/autobox.so (gdb) bt #0 0x00007ffff4951d97 in ?? () from /usr/lib/perl5/auto/autobox/autobox.so #1 0x00007ffff495201e in autobox_method_named () from /usr/lib/perl5/auto/autobox/autobox.so #2 0x00007ffff7b1b336 in Perl_runops_standard () from /usr/lib/libperl.so.5.10 #3 0x00007ffff7ac28cf in Perl_call_sv () from /usr/lib/libperl.so.5.10 #4 0x00007ffff7b2f6d6 in Perl_sv_clear () from /usr/lib/libperl.so.5.10 #5 0x00007ffff7b2fed2 in Perl_sv_free2 () from /usr/lib/libperl.so.5.10 #6 0x00007ffff7b24e22 in ?? () from /usr/lib/libperl.so.5.10 #7 0x00007ffff7b24e81 in Perl_sv_clean_objs () from /usr/lib/libperl.so.5.10 #8 0x00007ffff7ac4be9 in perl_destruct () from /usr/lib/libperl.so.5.10 #9 0x0000000000400d1c in main () (gdb) call (void*)Perl_get_context() $1 = (void *) 0x603010 (gdb) call (void*)Perl_eval_pv((void*)Perl_get_context(),"eval{require Carp; Carp::cluck(q{HERE});}", 0) HERE at (eval 5012) line 1 eval {...} called at (eval 5012) line 1 eval 'eval{require Carp; Carp::cluck(q{HERE});} ;' called at /usr/share/perl5/state51/Logger/Rabbit.pm line 138 state51::Logger::Rabbit::_has_unflushed_messages('state51::Logger::Rabbit=HASH(0x1f22d78)') called at /usr/share/perl5/state51/Logger/Rabbit.pm line 161 state51::Logger::Rabbit::idle('state51::Logger::Rabbit=HASH(0x1f22d78)') called at /usr/share/perl5/state51/Logger/Rabbit.pm line 152 state51::Logger::Rabbit::block_till_all_messages_sent('state51::Logger::Rabbit=HASH(0x1f22d78)') called at /usr/share/perl5/state51/Logger/Rabbit.pm line 148 state51::Logger::Rabbit::DEMOLISH('state51::Logger::Rabbit=HASH(0x1f22d78)', 1) called at /usr/lib/perl5/Moose/Object.pm line 87 Moose::Object::DEMOLISHALL('state51::Logger::Rabbit=HASH(0x1f22d78)', 1) called at /usr/lib/perl5/Moose/Object.pm line 98 Moose::Object::__ANON__() called at /usr/share/perl5/Try/Tiny.pm line 76 eval {...} called at /usr/share/perl5/Try/Tiny.pm line 67 Try::Tiny::try('CODE(0x2de1d60)', 'Try::Tiny::Catch=REF(0x3deee20)') called at /usr/lib/perl5/Moose/Object.pm line 102 Moose::Object::DESTROY('state51::Logger::Rabbit=HASH(0x1f22d78)') called at (eval 5012) line 0 eval {...} called at (eval 5012) line 0 $2 = (void *) 0x2dd9390 And the snipped of code in question for where I really found the bug: sub _has_unflushed_messages { my $self = shift; my $needs_wait = 0; foreach my $queue_name ($self->_local_queue_names) { my $lqueue = $self->_get_local_queue_for($queue_name); # We get $lqueue = undef here, try to call a method on it below, segfault! if ($lqueue->depth) { $needs_wait = 1; last; } } return $needs_wait; } Thanks in advance.
Thanks for the report and sorry for the late reply. I can't reproduce this segfault with the latest version of autobox (2.79). The test still fails[1], but I'm not sure if that has anything to do with this issue, which may have been fixed in 2.78: https://rt.cpan.org/Ticket/Display.html?id=80400 [1] # Failed test at test.pl line 5. # got: '11' # expected: '0' If you still have access to the original bug-exposing code, could you test it against autobox 2.79? Thanks, chocolateboy. On Wed Oct 19 08:33:23 2011, BOBTFISH wrote: Show quoted text
> I have extracted a standalone test case from my work code which was > causing the failure: > > use strict; > use warnings; > use Test::More; > > is system('/usr/bin/perl', '-e', q{{ > package Foo; > use Moose::Autobox; > sub get_bar { $_[0]->{bar} } > sub foo {} > sub DESTROY { $_->[0]->get_bar->bar } > } > { > package Bar; > use Moose::Autobox; > sub get_foo { $_->[0]->{foo} } > sub bar {} > sub DESTROY { $_->[0]->get_foo->foo } > } > my $foo = bless {}, 'Foo'; > my $bar = bless { foo => $foo }, 'Bar'; > $foo->{bar} = $bar; > exit(0); > }), 0; > done_testing; > > The above fails (as the script segfaults), however it works perfectly > without the Moose::Autobox being added (but not used anywhere). > > This fails for me on both i386 linux and i386 darwin. > > Backtrace from this happening in 'real' code: > > Program received signal SIGSEGV, Segmentation fault. > 0x00007ffff4951d97 in ?? () from > /usr/lib/perl5/auto/autobox/autobox.so > (gdb) bt > #0 0x00007ffff4951d97 in ?? () from > /usr/lib/perl5/auto/autobox/autobox.so > #1 0x00007ffff495201e in autobox_method_named () > from /usr/lib/perl5/auto/autobox/autobox.so > #2 0x00007ffff7b1b336 in Perl_runops_standard () from > /usr/lib/libperl.so.5.10 > #3 0x00007ffff7ac28cf in Perl_call_sv () from > /usr/lib/libperl.so.5.10 > #4 0x00007ffff7b2f6d6 in Perl_sv_clear () from > /usr/lib/libperl.so.5.10 > #5 0x00007ffff7b2fed2 in Perl_sv_free2 () from > /usr/lib/libperl.so.5.10 > #6 0x00007ffff7b24e22 in ?? () from /usr/lib/libperl.so.5.10 > #7 0x00007ffff7b24e81 in Perl_sv_clean_objs () from > /usr/lib/libperl.so.5.10 > #8 0x00007ffff7ac4be9 in perl_destruct () from > /usr/lib/libperl.so.5.10 > #9 0x0000000000400d1c in main () > (gdb) call (void*)Perl_get_context() > $1 = (void *) 0x603010 > (gdb) call (void*)Perl_eval_pv((void*)Perl_get_context(),"eval{require > Carp; Carp::cluck(q{HERE});}", 0) > HERE at (eval 5012) line 1 > eval {...} called at (eval 5012) line 1 > eval 'eval{require Carp; Carp::cluck(q{HERE});} > ;' called at /usr/share/perl5/state51/Logger/Rabbit.pm line 138 > > state51::Logger::Rabbit::_has_unflushed_messages('state51::Logger::Rabbit=HASH(0x1f22d78)') > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 161 > > state51::Logger::Rabbit::idle('state51::Logger::Rabbit=HASH(0x1f22d78)') > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 152 > > state51::Logger::Rabbit::block_till_all_messages_sent('state51::Logger::Rabbit=HASH(0x1f22d78)') > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 148 > > state51::Logger::Rabbit::DEMOLISH('state51::Logger::Rabbit=HASH(0x1f22d78)', > 1) called at /usr/lib/perl5/Moose/Object.pm line 87 > > Moose::Object::DEMOLISHALL('state51::Logger::Rabbit=HASH(0x1f22d78)', > 1) > called at /usr/lib/perl5/Moose/Object.pm line 98 > Moose::Object::__ANON__() called at > /usr/share/perl5/Try/Tiny.pm > line 76 > eval {...} called at /usr/share/perl5/Try/Tiny.pm line 67 > Try::Tiny::try('CODE(0x2de1d60)', > 'Try::Tiny::Catch=REF(0x3deee20)') called at > /usr/lib/perl5/Moose/Object.pm line 102 > > Moose::Object::DESTROY('state51::Logger::Rabbit=HASH(0x1f22d78)') > called > at (eval 5012) line 0 > eval {...} called at (eval 5012) line 0 > $2 = (void *) 0x2dd9390 > > And the snipped of code in question for where I really found the bug: > > sub _has_unflushed_messages { > my $self = shift; > my $needs_wait = 0; > foreach my $queue_name ($self->_local_queue_names) { > my $lqueue = $self->_get_local_queue_for($queue_name); # We > get > $lqueue = undef here, try to call a method on it below, segfault! > if ($lqueue->depth) { > $needs_wait = 1; > last; > } > } > return $needs_wait; > } > > Thanks in advance.
Show quoted text
> > I can't reproduce this segfault with the latest version of autobox
Scrub that. It's still occurring with 2.79. On Fri Oct 25 12:14:36 2013, CHOCOLATE wrote: Show quoted text
> Thanks for the report and sorry for the late reply. > > I can't reproduce this segfault with the latest version of autobox > (2.79). The test still fails[1], but I'm not sure if that has anything > to do with this issue, which may have been fixed in 2.78: > https://rt.cpan.org/Ticket/Display.html?id=80400 > > [1] > > # Failed test at test.pl line 5. > # got: '11' > # expected: '0' > > If you still have access to the original bug-exposing code, could you > test it against autobox 2.79? > > Thanks, > chocolateboy. > > On Wed Oct 19 08:33:23 2011, BOBTFISH wrote:
> > I have extracted a standalone test case from my work code which was > > causing the failure: > > > > use strict; > > use warnings; > > use Test::More; > > > > is system('/usr/bin/perl', '-e', q{{ > > package Foo; > > use Moose::Autobox; > > sub get_bar { $_[0]->{bar} } > > sub foo {} > > sub DESTROY { $_->[0]->get_bar->bar } > > } > > { > > package Bar; > > use Moose::Autobox; > > sub get_foo { $_->[0]->{foo} } > > sub bar {} > > sub DESTROY { $_->[0]->get_foo->foo } > > } > > my $foo = bless {}, 'Foo'; > > my $bar = bless { foo => $foo }, 'Bar'; > > $foo->{bar} = $bar; > > exit(0); > > }), 0; > > done_testing; > > > > The above fails (as the script segfaults), however it works perfectly > > without the Moose::Autobox being added (but not used anywhere). > > > > This fails for me on both i386 linux and i386 darwin. > > > > Backtrace from this happening in 'real' code: > > > > Program received signal SIGSEGV, Segmentation fault. > > 0x00007ffff4951d97 in ?? () from > > /usr/lib/perl5/auto/autobox/autobox.so > > (gdb) bt > > #0 0x00007ffff4951d97 in ?? () from > > /usr/lib/perl5/auto/autobox/autobox.so > > #1 0x00007ffff495201e in autobox_method_named () > > from /usr/lib/perl5/auto/autobox/autobox.so > > #2 0x00007ffff7b1b336 in Perl_runops_standard () from > > /usr/lib/libperl.so.5.10 > > #3 0x00007ffff7ac28cf in Perl_call_sv () from > > /usr/lib/libperl.so.5.10 > > #4 0x00007ffff7b2f6d6 in Perl_sv_clear () from > > /usr/lib/libperl.so.5.10 > > #5 0x00007ffff7b2fed2 in Perl_sv_free2 () from > > /usr/lib/libperl.so.5.10 > > #6 0x00007ffff7b24e22 in ?? () from /usr/lib/libperl.so.5.10 > > #7 0x00007ffff7b24e81 in Perl_sv_clean_objs () from > > /usr/lib/libperl.so.5.10 > > #8 0x00007ffff7ac4be9 in perl_destruct () from > > /usr/lib/libperl.so.5.10 > > #9 0x0000000000400d1c in main () > > (gdb) call (void*)Perl_get_context() > > $1 = (void *) 0x603010 > > (gdb) call > > (void*)Perl_eval_pv((void*)Perl_get_context(),"eval{require > > Carp; Carp::cluck(q{HERE});}", 0) > > HERE at (eval 5012) line 1 > > eval {...} called at (eval 5012) line 1 > > eval 'eval{require Carp; Carp::cluck(q{HERE});} > > ;' called at /usr/share/perl5/state51/Logger/Rabbit.pm line 138 > > > > state51::Logger::Rabbit::_has_unflushed_messages('state51::Logger::Rabbit=HASH(0x1f22d78)') > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 161 > > > > state51::Logger::Rabbit::idle('state51::Logger::Rabbit=HASH(0x1f22d78)') > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 152 > > > > state51::Logger::Rabbit::block_till_all_messages_sent('state51::Logger::Rabbit=HASH(0x1f22d78)') > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 148 > > > > state51::Logger::Rabbit::DEMOLISH('state51::Logger::Rabbit=HASH(0x1f22d78)', > > 1) called at /usr/lib/perl5/Moose/Object.pm line 87 > > > > Moose::Object::DEMOLISHALL('state51::Logger::Rabbit=HASH(0x1f22d78)', > > 1) > > called at /usr/lib/perl5/Moose/Object.pm line 98 > > Moose::Object::__ANON__() called at > > /usr/share/perl5/Try/Tiny.pm > > line 76 > > eval {...} called at /usr/share/perl5/Try/Tiny.pm line 67 > > Try::Tiny::try('CODE(0x2de1d60)', > > 'Try::Tiny::Catch=REF(0x3deee20)') called at > > /usr/lib/perl5/Moose/Object.pm line 102 > > > > Moose::Object::DESTROY('state51::Logger::Rabbit=HASH(0x1f22d78)') > > called > > at (eval 5012) line 0 > > eval {...} called at (eval 5012) line 0 > > $2 = (void *) 0x2dd9390 > > > > And the snipped of code in question for where I really found the bug: > > > > sub _has_unflushed_messages { > > my $self = shift; > > my $needs_wait = 0; > > foreach my $queue_name ($self->_local_queue_names) { > > my $lqueue = $self->_get_local_queue_for($queue_name); # We > > get > > $lqueue = undef here, try to call a method on it below, segfault! > > if ($lqueue->depth) { > > $needs_wait = 1; > > last; > > } > > } > > return $needs_wait; > > } > > > > Thanks in advance.
Simplified test case: use strict; use warnings; { package Foo; use autobox; sub DESTROY { $_[0]->{bar}->bar } } { package Bar; sub bar { } } my $foo = bless {}, 'Foo'; my $bar = bless {}, 'Bar'; $foo->{bar} = $bar; $bar->{foo} = $foo; On Fri Oct 25 13:02:11 2013, CHOCOLATE wrote: Show quoted text
> > > I can't reproduce this segfault with the latest version of autobox
> > Scrub that. It's still occurring with 2.79. > > On Fri Oct 25 12:14:36 2013, CHOCOLATE wrote:
> > Thanks for the report and sorry for the late reply. > > > > I can't reproduce this segfault with the latest version of autobox > > (2.79). The test still fails[1], but I'm not sure if that has > > anything > > to do with this issue, which may have been fixed in 2.78: > > https://rt.cpan.org/Ticket/Display.html?id=80400 > > > > [1] > > > > # Failed test at test.pl line 5. > > # got: '11' > > # expected: '0' > > > > If you still have access to the original bug-exposing code, could you > > test it against autobox 2.79? > > > > Thanks, > > chocolateboy. > > > > On Wed Oct 19 08:33:23 2011, BOBTFISH wrote:
> > > I have extracted a standalone test case from my work code which was > > > causing the failure: > > > > > > use strict; > > > use warnings; > > > use Test::More; > > > > > > is system('/usr/bin/perl', '-e', q{{ > > > package Foo; > > > use Moose::Autobox; > > > sub get_bar { $_[0]->{bar} } > > > sub foo {} > > > sub DESTROY { $_->[0]->get_bar->bar } > > > } > > > { > > > package Bar; > > > use Moose::Autobox; > > > sub get_foo { $_->[0]->{foo} } > > > sub bar {} > > > sub DESTROY { $_->[0]->get_foo->foo } > > > } > > > my $foo = bless {}, 'Foo'; > > > my $bar = bless { foo => $foo }, 'Bar'; > > > $foo->{bar} = $bar; > > > exit(0); > > > }), 0; > > > done_testing; > > > > > > The above fails (as the script segfaults), however it works > > > perfectly > > > without the Moose::Autobox being added (but not used anywhere). > > > > > > This fails for me on both i386 linux and i386 darwin. > > > > > > Backtrace from this happening in 'real' code: > > > > > > Program received signal SIGSEGV, Segmentation fault. > > > 0x00007ffff4951d97 in ?? () from > > > /usr/lib/perl5/auto/autobox/autobox.so > > > (gdb) bt > > > #0 0x00007ffff4951d97 in ?? () from > > > /usr/lib/perl5/auto/autobox/autobox.so > > > #1 0x00007ffff495201e in autobox_method_named () > > > from /usr/lib/perl5/auto/autobox/autobox.so > > > #2 0x00007ffff7b1b336 in Perl_runops_standard () from > > > /usr/lib/libperl.so.5.10 > > > #3 0x00007ffff7ac28cf in Perl_call_sv () from > > > /usr/lib/libperl.so.5.10 > > > #4 0x00007ffff7b2f6d6 in Perl_sv_clear () from > > > /usr/lib/libperl.so.5.10 > > > #5 0x00007ffff7b2fed2 in Perl_sv_free2 () from > > > /usr/lib/libperl.so.5.10 > > > #6 0x00007ffff7b24e22 in ?? () from /usr/lib/libperl.so.5.10 > > > #7 0x00007ffff7b24e81 in Perl_sv_clean_objs () from > > > /usr/lib/libperl.so.5.10 > > > #8 0x00007ffff7ac4be9 in perl_destruct () from > > > /usr/lib/libperl.so.5.10 > > > #9 0x0000000000400d1c in main () > > > (gdb) call (void*)Perl_get_context() > > > $1 = (void *) 0x603010 > > > (gdb) call > > > (void*)Perl_eval_pv((void*)Perl_get_context(),"eval{require > > > Carp; Carp::cluck(q{HERE});}", 0) > > > HERE at (eval 5012) line 1 > > > eval {...} called at (eval 5012) line 1 > > > eval 'eval{require Carp; Carp::cluck(q{HERE});} > > > ;' called at /usr/share/perl5/state51/Logger/Rabbit.pm line 138 > > > > > > state51::Logger::Rabbit::_has_unflushed_messages('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 161 > > > > > > state51::Logger::Rabbit::idle('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 152 > > > > > > state51::Logger::Rabbit::block_till_all_messages_sent('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 148 > > > > > > state51::Logger::Rabbit::DEMOLISH('state51::Logger::Rabbit=HASH(0x1f22d78)', > > > 1) called at /usr/lib/perl5/Moose/Object.pm line 87 > > > > > > Moose::Object::DEMOLISHALL('state51::Logger::Rabbit=HASH(0x1f22d78)', > > > 1) > > > called at /usr/lib/perl5/Moose/Object.pm line 98 > > > Moose::Object::__ANON__() called at > > > /usr/share/perl5/Try/Tiny.pm > > > line 76 > > > eval {...} called at /usr/share/perl5/Try/Tiny.pm line 67 > > > Try::Tiny::try('CODE(0x2de1d60)', > > > 'Try::Tiny::Catch=REF(0x3deee20)') called at > > > /usr/lib/perl5/Moose/Object.pm line 102 > > > > > > Moose::Object::DESTROY('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > called > > > at (eval 5012) line 0 > > > eval {...} called at (eval 5012) line 0 > > > $2 = (void *) 0x2dd9390 > > > > > > And the snipped of code in question for where I really found the > > > bug: > > > > > > sub _has_unflushed_messages { > > > my $self = shift; > > > my $needs_wait = 0; > > > foreach my $queue_name ($self->_local_queue_names) { > > > my $lqueue = $self->_get_local_queue_for($queue_name); # We > > > get > > > $lqueue = undef here, try to call a method on it below, segfault! > > > if ($lqueue->depth) { > > > $needs_wait = 1; > > > last; > > > } > > > } > > > return $needs_wait; > > > } > > > > > > Thanks in advance.
The problem: autobox allocates an internal data structure (via B::Hooks::OP::Annotation) which needs to be accessed each time a method compiled under "use autobox" is resolved (at runtime). Currently this data structure is freed during global destruction (during the DESTRUCT[1] phase). In theory, destructors for non-package variables should run during the preceeding phase (RUN), but the circular reference in the test case breaks that i.e. the destructor of a non-package variable may be called after DESTRUCT (XXX this should probably be documented in perlvar). [1] http://perldoc.perl.org/perlvar.html#${^GLOBAL_PHASE} There are 2 solutions: 1) don't free the internal data structure (i.e. leave cleanup to the OS) 2) don't allow autoboxing after the internal data structure has been freed (i.e. dispatch those method calls as normal) The problem with 1) is that allocating something without freeing it is a bad practice (i.e. a memory leak), even if the operating system allows one to get away with it. There may even be some platforms that perl runs on that don't clean up that allocated memory (Windows 98?). The problem with 2) is that it makes autoboxing silently not work (in certain types of destructor). Destructors are fiddly enough to debug already without adding more surprises. I could add a caveat saying "don't use autobox in destructors", I guess. Either fix is easy to implement, but the ideal solution would be for perl to provide a hook (e.g. EXIT, SHUTDOWN or CLEANUP) that's called after *all* code/blocks/destructors have run. In the absence of that, I'll probably go with 1) (as suggested in the other ticket), but I wish there was a saner solution... Thanks, chocolateboy. On Fri Oct 25 13:52:42 2013, CHOCOLATE wrote: Show quoted text
> Simplified test case: > > use strict; > use warnings; > > { > package Foo; > use autobox; > sub DESTROY { $_[0]->{bar}->bar } > } > > { > package Bar; > sub bar { } > } > > my $foo = bless {}, 'Foo'; > my $bar = bless {}, 'Bar'; > > $foo->{bar} = $bar; > $bar->{foo} = $foo; > > On Fri Oct 25 13:02:11 2013, CHOCOLATE wrote:
> > > > I can't reproduce this segfault with the latest version of > > > > autobox
> > > > Scrub that. It's still occurring with 2.79. > > > > On Fri Oct 25 12:14:36 2013, CHOCOLATE wrote:
> > > Thanks for the report and sorry for the late reply. > > > > > > I can't reproduce this segfault with the latest version of autobox > > > (2.79). The test still fails[1], but I'm not sure if that has > > > anything > > > to do with this issue, which may have been fixed in 2.78: > > > https://rt.cpan.org/Ticket/Display.html?id=80400 > > > > > > [1] > > > > > > # Failed test at test.pl line 5. > > > # got: '11' > > > # expected: '0' > > > > > > If you still have access to the original bug-exposing code, could > > > you > > > test it against autobox 2.79? > > > > > > Thanks, > > > chocolateboy. > > > > > > On Wed Oct 19 08:33:23 2011, BOBTFISH wrote:
> > > > I have extracted a standalone test case from my work code which > > > > was > > > > causing the failure: > > > > > > > > use strict; > > > > use warnings; > > > > use Test::More; > > > > > > > > is system('/usr/bin/perl', '-e', q{{ > > > > package Foo; > > > > use Moose::Autobox; > > > > sub get_bar { $_[0]->{bar} } > > > > sub foo {} > > > > sub DESTROY { $_->[0]->get_bar->bar } > > > > } > > > > { > > > > package Bar; > > > > use Moose::Autobox; > > > > sub get_foo { $_->[0]->{foo} } > > > > sub bar {} > > > > sub DESTROY { $_->[0]->get_foo->foo } > > > > } > > > > my $foo = bless {}, 'Foo'; > > > > my $bar = bless { foo => $foo }, 'Bar'; > > > > $foo->{bar} = $bar; > > > > exit(0); > > > > }), 0; > > > > done_testing; > > > > > > > > The above fails (as the script segfaults), however it works > > > > perfectly > > > > without the Moose::Autobox being added (but not used anywhere). > > > > > > > > This fails for me on both i386 linux and i386 darwin. > > > > > > > > Backtrace from this happening in 'real' code: > > > > > > > > Program received signal SIGSEGV, Segmentation fault. > > > > 0x00007ffff4951d97 in ?? () from > > > > /usr/lib/perl5/auto/autobox/autobox.so > > > > (gdb) bt > > > > #0 0x00007ffff4951d97 in ?? () from > > > > /usr/lib/perl5/auto/autobox/autobox.so > > > > #1 0x00007ffff495201e in autobox_method_named () > > > > from /usr/lib/perl5/auto/autobox/autobox.so > > > > #2 0x00007ffff7b1b336 in Perl_runops_standard () from > > > > /usr/lib/libperl.so.5.10 > > > > #3 0x00007ffff7ac28cf in Perl_call_sv () from > > > > /usr/lib/libperl.so.5.10 > > > > #4 0x00007ffff7b2f6d6 in Perl_sv_clear () from > > > > /usr/lib/libperl.so.5.10 > > > > #5 0x00007ffff7b2fed2 in Perl_sv_free2 () from > > > > /usr/lib/libperl.so.5.10 > > > > #6 0x00007ffff7b24e22 in ?? () from /usr/lib/libperl.so.5.10 > > > > #7 0x00007ffff7b24e81 in Perl_sv_clean_objs () from > > > > /usr/lib/libperl.so.5.10 > > > > #8 0x00007ffff7ac4be9 in perl_destruct () from > > > > /usr/lib/libperl.so.5.10 > > > > #9 0x0000000000400d1c in main () > > > > (gdb) call (void*)Perl_get_context() > > > > $1 = (void *) 0x603010 > > > > (gdb) call > > > > (void*)Perl_eval_pv((void*)Perl_get_context(),"eval{require > > > > Carp; Carp::cluck(q{HERE});}", 0) > > > > HERE at (eval 5012) line 1 > > > > eval {...} called at (eval 5012) line 1 > > > > eval 'eval{require Carp; Carp::cluck(q{HERE});} > > > > ;' called at /usr/share/perl5/state51/Logger/Rabbit.pm line 138 > > > > > > > > state51::Logger::Rabbit::_has_unflushed_messages('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 161 > > > > > > > > state51::Logger::Rabbit::idle('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 152 > > > > > > > > state51::Logger::Rabbit::block_till_all_messages_sent('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 148 > > > > > > > > state51::Logger::Rabbit::DEMOLISH('state51::Logger::Rabbit=HASH(0x1f22d78)', > > > > 1) called at /usr/lib/perl5/Moose/Object.pm line 87 > > > > > > > > Moose::Object::DEMOLISHALL('state51::Logger::Rabbit=HASH(0x1f22d78)', > > > > 1) > > > > called at /usr/lib/perl5/Moose/Object.pm line 98 > > > > Moose::Object::__ANON__() called at > > > > /usr/share/perl5/Try/Tiny.pm > > > > line 76 > > > > eval {...} called at /usr/share/perl5/Try/Tiny.pm line 67 > > > > Try::Tiny::try('CODE(0x2de1d60)', > > > > 'Try::Tiny::Catch=REF(0x3deee20)') called at > > > > /usr/lib/perl5/Moose/Object.pm line 102 > > > > > > > > Moose::Object::DESTROY('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > > called > > > > at (eval 5012) line 0 > > > > eval {...} called at (eval 5012) line 0 > > > > $2 = (void *) 0x2dd9390 > > > > > > > > And the snipped of code in question for where I really found the > > > > bug: > > > > > > > > sub _has_unflushed_messages { > > > > my $self = shift; > > > > my $needs_wait = 0; > > > > foreach my $queue_name ($self->_local_queue_names) { > > > > my $lqueue = $self->_get_local_queue_for($queue_name); # > > > > We > > > > get > > > > $lqueue = undef here, try to call a method on it below, segfault! > > > > if ($lqueue->depth) { > > > > $needs_wait = 1; > > > > last; > > > > } > > > > } > > > > return $needs_wait; > > > > } > > > > > > > > Thanks in advance.
Solved: perl provides a function called Perl_call_atexit, which allows callbacks to be registered that are called after global destruction. I've just uploaded 2.80, which includes this fix. Thanks again, chocoolateboy. On Fri Oct 25 15:27:52 2013, CHOCOLATE wrote: Show quoted text
> The problem: autobox allocates an internal data structure (via > B::Hooks::OP::Annotation) which needs to be accessed each time a > method compiled under "use autobox" is resolved (at runtime). > Currently this data structure is freed during global destruction > (during the DESTRUCT[1] phase). In theory, destructors for non-package > variables should run during the preceeding phase (RUN), but the > circular reference in the test case breaks that i.e. the destructor of > a non-package variable may be called after DESTRUCT (XXX this should > probably be documented in perlvar). > > [1] http://perldoc.perl.org/perlvar.html#${^GLOBAL_PHASE} > > There are 2 solutions: > > 1) don't free the internal data structure (i.e. leave cleanup to the > OS) > > 2) don't allow autoboxing after the internal data structure has been > freed (i.e. dispatch those method calls as normal) > > The problem with 1) is that allocating something without freeing it is > a bad practice (i.e. a memory leak), even if the operating system > allows one to get away with it. There may even be some platforms that > perl runs on that don't clean up that allocated memory (Windows 98?). > > The problem with 2) is that it makes autoboxing silently not work (in > certain types of destructor). Destructors are fiddly enough to debug > already without adding more surprises. I could add a caveat saying > "don't use autobox in destructors", I guess. > > Either fix is easy to implement, but the ideal solution would be for > perl to provide a hook (e.g. EXIT, SHUTDOWN or CLEANUP) that's called > after *all* code/blocks/destructors have run. In the absence of that, > I'll probably go with 1) (as suggested in the other ticket), but I > wish there was a saner solution... > > Thanks, > chocolateboy. > > On Fri Oct 25 13:52:42 2013, CHOCOLATE wrote:
> > Simplified test case: > > > > use strict; > > use warnings; > > > > { > > package Foo; > > use autobox; > > sub DESTROY { $_[0]->{bar}->bar } > > } > > > > { > > package Bar; > > sub bar { } > > } > > > > my $foo = bless {}, 'Foo'; > > my $bar = bless {}, 'Bar'; > > > > $foo->{bar} = $bar; > > $bar->{foo} = $foo; > > > > On Fri Oct 25 13:02:11 2013, CHOCOLATE wrote:
> > > > > I can't reproduce this segfault with the latest version of > > > > > autobox
> > > > > > Scrub that. It's still occurring with 2.79. > > > > > > On Fri Oct 25 12:14:36 2013, CHOCOLATE wrote:
> > > > Thanks for the report and sorry for the late reply. > > > > > > > > I can't reproduce this segfault with the latest version of > > > > autobox > > > > (2.79). The test still fails[1], but I'm not sure if that has > > > > anything > > > > to do with this issue, which may have been fixed in 2.78: > > > > https://rt.cpan.org/Ticket/Display.html?id=80400 > > > > > > > > [1] > > > > > > > > # Failed test at test.pl line 5. > > > > # got: '11' > > > > # expected: '0' > > > > > > > > If you still have access to the original bug-exposing code, could > > > > you > > > > test it against autobox 2.79? > > > > > > > > Thanks, > > > > chocolateboy. > > > > > > > > On Wed Oct 19 08:33:23 2011, BOBTFISH wrote:
> > > > > I have extracted a standalone test case from my work code which > > > > > was > > > > > causing the failure: > > > > > > > > > > use strict; > > > > > use warnings; > > > > > use Test::More; > > > > > > > > > > is system('/usr/bin/perl', '-e', q{{ > > > > > package Foo; > > > > > use Moose::Autobox; > > > > > sub get_bar { $_[0]->{bar} } > > > > > sub foo {} > > > > > sub DESTROY { $_->[0]->get_bar->bar } > > > > > } > > > > > { > > > > > package Bar; > > > > > use Moose::Autobox; > > > > > sub get_foo { $_->[0]->{foo} } > > > > > sub bar {} > > > > > sub DESTROY { $_->[0]->get_foo->foo } > > > > > } > > > > > my $foo = bless {}, 'Foo'; > > > > > my $bar = bless { foo => $foo }, 'Bar'; > > > > > $foo->{bar} = $bar; > > > > > exit(0); > > > > > }), 0; > > > > > done_testing; > > > > > > > > > > The above fails (as the script segfaults), however it works > > > > > perfectly > > > > > without the Moose::Autobox being added (but not used anywhere). > > > > > > > > > > This fails for me on both i386 linux and i386 darwin. > > > > > > > > > > Backtrace from this happening in 'real' code: > > > > > > > > > > Program received signal SIGSEGV, Segmentation fault. > > > > > 0x00007ffff4951d97 in ?? () from > > > > > /usr/lib/perl5/auto/autobox/autobox.so > > > > > (gdb) bt > > > > > #0 0x00007ffff4951d97 in ?? () from > > > > > /usr/lib/perl5/auto/autobox/autobox.so > > > > > #1 0x00007ffff495201e in autobox_method_named () > > > > > from /usr/lib/perl5/auto/autobox/autobox.so > > > > > #2 0x00007ffff7b1b336 in Perl_runops_standard () from > > > > > /usr/lib/libperl.so.5.10 > > > > > #3 0x00007ffff7ac28cf in Perl_call_sv () from > > > > > /usr/lib/libperl.so.5.10 > > > > > #4 0x00007ffff7b2f6d6 in Perl_sv_clear () from > > > > > /usr/lib/libperl.so.5.10 > > > > > #5 0x00007ffff7b2fed2 in Perl_sv_free2 () from > > > > > /usr/lib/libperl.so.5.10 > > > > > #6 0x00007ffff7b24e22 in ?? () from /usr/lib/libperl.so.5.10 > > > > > #7 0x00007ffff7b24e81 in Perl_sv_clean_objs () from > > > > > /usr/lib/libperl.so.5.10 > > > > > #8 0x00007ffff7ac4be9 in perl_destruct () from > > > > > /usr/lib/libperl.so.5.10 > > > > > #9 0x0000000000400d1c in main () > > > > > (gdb) call (void*)Perl_get_context() > > > > > $1 = (void *) 0x603010 > > > > > (gdb) call > > > > > (void*)Perl_eval_pv((void*)Perl_get_context(),"eval{require > > > > > Carp; Carp::cluck(q{HERE});}", 0) > > > > > HERE at (eval 5012) line 1 > > > > > eval {...} called at (eval 5012) line 1 > > > > > eval 'eval{require Carp; Carp::cluck(q{HERE});} > > > > > ;' called at /usr/share/perl5/state51/Logger/Rabbit.pm line 138 > > > > > > > > > > state51::Logger::Rabbit::_has_unflushed_messages('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 161 > > > > > > > > > > state51::Logger::Rabbit::idle('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 152 > > > > > > > > > > state51::Logger::Rabbit::block_till_all_messages_sent('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > > > called at /usr/share/perl5/state51/Logger/Rabbit.pm line 148 > > > > > > > > > > state51::Logger::Rabbit::DEMOLISH('state51::Logger::Rabbit=HASH(0x1f22d78)', > > > > > 1) called at /usr/lib/perl5/Moose/Object.pm line 87 > > > > > > > > > > Moose::Object::DEMOLISHALL('state51::Logger::Rabbit=HASH(0x1f22d78)', > > > > > 1) > > > > > called at /usr/lib/perl5/Moose/Object.pm line 98 > > > > > Moose::Object::__ANON__() called at > > > > > /usr/share/perl5/Try/Tiny.pm > > > > > line 76 > > > > > eval {...} called at /usr/share/perl5/Try/Tiny.pm line > > > > > 67 > > > > > Try::Tiny::try('CODE(0x2de1d60)', > > > > > 'Try::Tiny::Catch=REF(0x3deee20)') called at > > > > > /usr/lib/perl5/Moose/Object.pm line 102 > > > > > > > > > > Moose::Object::DESTROY('state51::Logger::Rabbit=HASH(0x1f22d78)') > > > > > called > > > > > at (eval 5012) line 0 > > > > > eval {...} called at (eval 5012) line 0 > > > > > $2 = (void *) 0x2dd9390 > > > > > > > > > > And the snipped of code in question for where I really found > > > > > the > > > > > bug: > > > > > > > > > > sub _has_unflushed_messages { > > > > > my $self = shift; > > > > > my $needs_wait = 0; > > > > > foreach my $queue_name ($self->_local_queue_names) { > > > > > my $lqueue = $self->_get_local_queue_for($queue_name); > > > > > # > > > > > We > > > > > get > > > > > $lqueue = undef here, try to call a method on it below, > > > > > segfault! > > > > > if ($lqueue->depth) { > > > > > $needs_wait = 1; > > > > > last; > > > > > } > > > > > } > > > > > return $needs_wait; > > > > > } > > > > > > > > > > Thanks in advance.