On Apr 2, 2011, at 10:36 AM, Andreas J. Koenig wrote:
Show quoted text> rt.cpan ticket:
> ---------------
>
>
https://rt.cpan.org/Ticket/Display.html?id=66921
>
> git bisect:
> -----------
>
> 2d0d1eccfcfe45f2fac66080cd30117a608088f8 is the first bad commit
> commit 2d0d1eccfcfe45f2fac66080cd30117a608088f8
> Author: Father Chrysostomos <sprout@cpan.org>
> Date: Mon Nov 15 14:30:07 2010 -0800
>
> [perl #79208] %stash:: = () anonymises CVs
>
> This keeps stash names visible during %foo:: = ().
>
> This fixes @ISA assignment inside a DESTROY method triggered by %foo::
> = () and also lets existing CVs retain their pointers to the stash.
>
> So
> %foo:: = ()
> is now equivalent to
> delete $foo::{$_} for keys %foo::
>
It can be reduced to this:
---
sub Foo::bar::DESTROY {
my $stash = delete $Foo::{"bar::"};
warn join " ", keys %Foo::; # Warning, something’s wrong
%$stash=();
warn join " ", keys %Foo::; # bar::
}
{ bless [], "Foo::bar"; }
---
What’s happening is that the %$stash assignment is causing the DESTROY glob to be freed. So the DESTROY sub (since it is active and therefore has an extra refcount and won’t be freed just yet) gets ‘anonymised’, that is, renamed to Foo::bar::__ANON__. (Before 5.13.7 it was renamed __ANON__::__ANON__.)
This is accomplished in S_anonymise_cv_maybe in sv.c, which makes the cv (DESTROY) point to that glob. So it ends up autovivifying the package. This is what happens also in previous releases if the stash assignment is replaced with ‘delete $$stash{$_} for keys %$stash’.
I think the best way to solve this is for S_anonymise_cv_maybe to use the stash’s effective name to fetch it’s *__ANON__ glob, to avoid autovivifying it. This will guarantee that, when it is trying to retain the pointer to the same stash (as opposed to %__ANON__::), it *will* be using the same stash, and not some other (possibly autovivified) stash that happened to have the same name. I think this was the original intent of this code anyway.
The user-visible effect of this will be that, when %$stash is no longer attached to the symbol table,
delete $$stash{$_} for keys %$stash
will no longer autovivify the stash that has just been deleted, but will rename Foo::bar::DESTROY to __ANON__::__ANON__. (I would consider this a bug fix, as it eliminates an existing memory leak.) And
%$stash = ();
will go back to renaming DESTROY to __ANON__::__ANON__, as it did in 5.13.6 and earlier.
Another noticeable effect is that this code:
sub Bar::baz{}
my $sub = \&Bar::baz;
*Foo:: = delete $::{"Bar::"};
delete $Foo::{baz};
will cause Bar::baz to be renamed Bar::__ANON__, as before, but behind the scenes it will point to the stash now at %Foo::, instead of autoviviying a new %Bar::.
Attached is a patch to do this.