summaryrefslogtreecommitdiff
path: root/op.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2013-07-28 12:35:47 -0700
committerFather Chrysostomos <sprout@cpan.org>2013-07-28 12:45:50 -0700
commit2f222bbdd2d6da605708c3ab620ac25c62481179 (patch)
treeb640f418b883e1c72f85fe763f5b31d86e61dd13 /op.c
parente82485c19c70d922047c43d035a5e59a7c08ce67 (diff)
downloadperl-2f222bbdd2d6da605708c3ab620ac25c62481179.tar.gz
[perl #119051] Fix crash with \&$glob_copy
$ref = *Foo::nosub; \&$ref; The assignment creates a glob copy (coercible glob; one that down- grades back to a simple scalar when assigned to). \&$ref autovivifies a stub in that glob. The CvGV pointer ends up pointing to $ref, rather than *Foo::nosub. $ref can easily cease being a glob. So crashes happen. Stub autovivification used to stringify the glob, look it up again by name, and then vivify the stub in the glob. In commit 186a5ba82d584 I removed what seemed like a waste of CPU cycles, but apparently it served some purpose. The lookup caused CvGV to point to *Foo::nosub, rather than $x. This commit restores the stringfy-and-lookup if the glob is coercible (SvFAKE). It goes a little further and turns off the SvFAKE flag if the glob just looked up is also FAKE. It turns out this bug is old, and has been triggerable via glob copies in stash elements for a long time. 186a5ba82d584 made it easier to trigger the bug (so it is a regression from 5.16).
Diffstat (limited to 'op.c')
-rw-r--r--op.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/op.c b/op.c
index e308d08911..7576509639 100644
--- a/op.c
+++ b/op.c
@@ -7918,13 +7918,19 @@ CV *
Perl_newSTUB(pTHX_ GV *gv, bool fake)
{
CV *cv = MUTABLE_CV(newSV_type(SVt_PVCV));
+ GV *cvgv;
PERL_ARGS_ASSERT_NEWSTUB;
assert(!GvCVu(gv));
GvCV_set(gv, cv);
GvCVGEN(gv) = 0;
if (!fake && HvENAME_HEK(GvSTASH(gv)))
gv_method_changed(gv);
- CvGV_set(cv, gv);
+ if (SvFAKE(gv)) {
+ cvgv = gv_fetchsv((SV *)gv, GV_ADDMULTI, SVt_PVCV);
+ SvFAKE_off(cvgv);
+ }
+ else cvgv = gv;
+ CvGV_set(cv, cvgv);
CvFILE_set_from_cop(cv, PL_curcop);
CvSTASH_set(cv, PL_curstash);
GvMULTI_on(gv);