diff options
author | Father Chrysostomos <sprout@cpan.org> | 2013-11-05 06:14:59 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2013-11-05 12:55:02 -0800 |
commit | 8941bf970eeb8009630d57a0b1bacb99f40db9bf (patch) | |
tree | 81f1d4eacc8f94d1ec19dce2e51931f0cc0c7cde /gv.c | |
parent | 3b927101bf18bfcb197cacec8603d2b8297963ae (diff) | |
download | perl-8941bf970eeb8009630d57a0b1bacb99f40db9bf.tar.gz |
Stop gv_try_downgrade from anonymising referenced CVs
I keep discovering ways in which gv_try_downgrade, which is supposed
to be an optimisation, changes observable behaviour even without look-
ing at the stash.
This one had me confused at first:
$ ./perl -Ilib -e 'use constant foo=>1; BEGIN { $x = \&foo } undef &$x; $x->()'
Undefined subroutine called at -e line 1.
$ ./perl -Ilib -e 'use constant foo=>1; BEGIN { $x = \&{"foo"} } undef &$x; $x->()'
Undefined subroutine &main::foo called at -e line 1.
Notice how the first example (where gv_try_downgrade kicks in)
shows no name in the error message. This only happens on non-
threaded builds.
What’s happening is that, when the BEGIN block is freed, the GV op
corresponding to &foo get freed, triggering gv_try_downgrade, which
checks to see whether it can downgrade the GV to a simple reference
to a constant (the way constants are stored by default). It then pro-
ceeds to do that, so the GV qua GV ceases to exist, and the CV gets
automatically anonymised as a result (the same thing happens with
‘$x = \&{"foo"}; Dump $x; delete $::{foo}’, but legitimately in
that case).
The solution here is to check the reference count on the CV before
downgrading the GV. If the CV’s reference count > 1, then we should
leave it alone.
Diffstat (limited to 'gv.c')
-rw-r--r-- | gv.c | 2 |
1 files changed, 1 insertions, 1 deletions
@@ -3345,7 +3345,7 @@ Perl_gv_try_downgrade(pTHX_ GV *gv) if (!cv) { HEK *gvnhek = GvNAME_HEK(gv); (void)hv_deletehek(stash, gvnhek, G_DISCARD); - } else if (GvMULTI(gv) && cv && + } else if (GvMULTI(gv) && cv && SvREFCNT(cv) == 1 && !SvOBJECT(cv) && !SvMAGICAL(cv) && !SvREADONLY(cv) && CvSTASH(cv) == stash && CvGV(cv) == gv && CvCONST(cv) && !CvMETHOD(cv) && !CvLVALUE(cv) && !CvUNIQUE(cv) && |