Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Storable CPAN distribution.

Report information
The Basics
Id: 36087
Status: open
Priority: 0/
Queue: Storable

People
Owner: Nobody in particular
Requestors: dom [...] cpan.org
martin.ferrari [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in:
  • 2.13
  • 2.15
  • 2.18
Fixed in: (no value)



Subject: segfaults when called during global destruction
This is apparently an old problem that went under the radar. It was already reported in May, 2005 in http://www.mail-archive.com/perl5-porters@perl.org/msg86928.html, but nobody could reproduce it at the time. Also it was discussed on http://www.perlmonks.org/?node_id=651966. I have tried the attached test in at least 4 different architectures (i386, ia64, armel and sparc64) in Debian, and also tried FreeBSD, RedHat, Mandriva and Gentoo. In every try, I got a segfault like this: $ perl test.pl Destroying Foo=HASH(0x6000000000009630), bar=baz at test.pl line 17 during global destruction. Segmentation fault $ uname -a Linux merulo 2.6.18-dsa-mckinley #1 SMP Mon Feb 11 09:57:09 MST 2008 ia64 GNU/Linux This seems to be the cause of -at least- http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=315669 Thanks.
Subject: test.pl
#!/usr/bin/perl use strict; use warnings; our $a = new Foo(); $a->{bar} = "baz"; package Foo; use Storable; sub new { return bless({}, "Foo"); } sub DESTROY { my $this = shift; warn "Destroying $this, bar=$this->{bar}"; my $f = Storable::freeze($this); }
RT-Send-CC: perl5-porters [...] perl.org
The testcase, for reference: #!/usr/bin/perl use strict; use warnings; our $a = new Foo(); $a->{bar} = "baz"; package Foo; use Storable; sub new { return bless({}, "Foo"); } sub DESTROY { my $this = shift; warn "Destroying $this, bar=$this->{bar}"; my $f = Storable::freeze($this); } Here's a workaround that Git instated due to this issue: http://github.com/git/git/commit/8ac3a667 I investigated it a bit, it's segfaulting at the very start of do_store(): here ==> dSTCXT; int status; When I manually expand that macro it ends up being: { SV *perinterp_sv = *hv_fetch(PL_modglobal, MY_VERSION, sizeof(MY_VERSION)-1, TRUE); stcxt_t * cxt; if (perinterp_sv && SvIOK(perinterp_sv) && SvIVX(perinterp_sv)) { IV x = SvIVX(perinterp_sv); void* ptr = INT2PTR(SV*,x); SV* rv = SvRV(ptr); => cxt = (stcxt_t *)SvPVX(rv); } else { cxt = (stcxt_t *) 0; } int status; ptr is an OK scalar, but its RV slot is NULL. Even if that call hadn't failed and cxt was set to 0 it would still segfault later in the function, e.g. here: if (cxt->s_dirty) clean_context(aTHX_ cxt); The problem is seemingly that Storable is looking at its own context during global destruction, but when it gets around to it perl has already started freeing the variables that it depends on. Looking at anything during global destruction is dangerous. Storable should either be fixed to hook into destruction earlier, or this limitation documented. Maybe there's also a workaround I haven't spotted.
CC: perl5-porters [...] perl.org
Subject: Re: [rt.cpan.org #36087] segfaults when called during global destruction
Date: Wed, 21 Jul 2010 06:57:41 -0700
To: bug-Storable [...] rt.cpan.org
From: Joshua ben Jore <twists [...] gmail.com>
On Tue, Jul 20, 2010 at 10:14 AM, AEvar Arnfjord Bjarmason via RT <bug-Storable@rt.cpan.org> wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=36087 > > > The testcase, for reference: > >    #!/usr/bin/perl > >    use strict; >    use warnings; > >    our $a = new Foo(); >    $a->{bar} = "baz"; > >    package Foo; >    use Storable; > >    sub new { >    return bless({}, "Foo"); >    } >    sub DESTROY { >    my $this = shift; >    warn "Destroying $this, bar=$this->{bar}"; >    my $f = Storable::freeze($this); >    } > > Here's a workaround that Git instated due to this issue: > http://github.com/git/git/commit/8ac3a667 > > I investigated it a bit, it's segfaulting at the very start of > do_store(): > >    here  ==> dSTCXT; >                  int status; > > When I manually expand that macro it ends up being: > >    { >        SV *perinterp_sv = *hv_fetch(PL_modglobal, >                                     MY_VERSION, sizeof(MY_VERSION)-1, > TRUE); >        stcxt_t * cxt; >        if (perinterp_sv && SvIOK(perinterp_sv) && SvIVX(perinterp_sv)) > { >            IV x = SvIVX(perinterp_sv); >            void* ptr = INT2PTR(SV*,x); >            SV* rv = SvRV(ptr); >    =>      cxt = (stcxt_t *)SvPVX(rv); >        } else { >            cxt = (stcxt_t *) 0; >        } >        int status; > > ptr is an OK scalar, but its RV slot is NULL. Even if that call hadn't > failed and cxt was set to 0 it would still segfault later in the > function, e.g. here: > >    if (cxt->s_dirty) >        clean_context(aTHX_ cxt); > > The problem is seemingly that Storable is looking at its own context > during global destruction, but when it gets around to it perl has > already started freeing the variables that it depends on. > > Looking at anything during global destruction is dangerous. Storable > should either be fixed to hook into destruction earlier, or this > limitation documented. Maybe there's also a workaround I haven't > spotted.
The problem as you described on IRC is that your Foo object is destroyed after Storable's object. There's relatively little that can be done with that under the current implementation which is that ->DESTROY calls have no promised order between objects. We could possibly however alter Storable's usage of its global object in $Storable::Cxt so it can be re-created when needed even during global destruction. Josh
This appears (as far as running test.pl is concerned) to have been fixed somewhere between perl 5.14.3 and perl 5.20.1 (ie Storable 2.27 and 2.49).