summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-09-01 16:16:32 -0700
committerFather Chrysostomos <sprout@cpan.org>2011-09-01 16:28:35 -0700
commitff55a0191f195519f46838f62b3cd22a95056579 (patch)
tree9d09e639d033888175da3e6a05ca4a1eb5926769
parentad66d0c9a62d4dfd3104dc78e5ed404470286bb6 (diff)
downloadperl-ff55a0191f195519f46838f62b3cd22a95056579.tar.gz
Fix two \&$tied regressions
If the tied variable holds a reference, but changes to something else when FETCH is called, perl crashes, as of commit 9d0f7ed75 (5.10.1/5.12.0): sub ::72 { 73 }; sub TIESCALAR {bless[]} sub STORE{} sub FETCH { 72 } tie my $x, "main"; $x = \$y; \&$x; That’s because commit 7a5fd60d4 caused double magic for one branch of an if/else chain in sv_2cv (by using gv_fetchsv), so commit 9d0f7ed75 removed the SvGETMAGIC preceding the if/else, putting it inside each branch. That meant that the type would be checked before get-magic was called. So the type could change unexpectedly. Due to another bug, this did not affect globs returned from tied array elements, which got stringified, and hence worked in sv_2cv. But that bug was fixed in 5.14.0 by commit 13be902ce, which allowed typeglobs to be returned unflattened through elements of tied aggregates, caus- ing this to stop working (‘Not a CODE reference’ instead of 73): sub ::72 { 73 }; sub TIEARRAY {bless[]} sub STORE{} sub FETCH { 72 } tie my @x, "main"; my $elem = \$x[0]; $$elem = *bar; print &{\&$$elem}, "\n"; This commit fixes both issues by putting the SvGETMAGIC call back where it belongs, above the if/else chain, and by using SvPV_nomg_const and gv_fetchpvn_flags instead of gv_fetchsv, to avoid an extra magic call.
-rw-r--r--sv.c12
-rw-r--r--t/op/tie.t26
2 files changed, 34 insertions, 4 deletions
diff --git a/sv.c b/sv.c
index 2acfafc683..ed3e264d03 100644
--- a/sv.c
+++ b/sv.c
@@ -8847,8 +8847,8 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **const st, GV **const gvp, const I32 lref)
/* FALL THROUGH */
default:
+ SvGETMAGIC(sv);
if (SvROK(sv)) {
- SvGETMAGIC(sv);
if (SvAMAGIC(sv))
sv = amagic_deref_call(sv, to_cv_amg);
/* At this point I'd like to do SPAGAIN, but really I need to
@@ -8867,11 +8867,15 @@ Perl_sv_2cv(pTHX_ SV *sv, HV **const st, GV **const gvp, const I32 lref)
Perl_croak(aTHX_ "Not a subroutine reference");
}
else if (isGV_with_GP(sv)) {
- SvGETMAGIC(sv);
gv = MUTABLE_GV(sv);
}
- else
- gv = gv_fetchsv(sv, lref, SVt_PVCV); /* Calls get magic */
+ else {
+ STRLEN len;
+ const char * const nambeg = SvPV_nomg_const(sv, len);
+ gv = gv_fetchpvn_flags(
+ nambeg, len, lref | SvUTF8(sv), SVt_PVCV
+ );
+ }
*gvp = gv;
if (!gv) {
*st = NULL;
diff --git a/t/op/tie.t b/t/op/tie.t
index 081379128f..d7a24540bd 100644
--- a/t/op/tie.t
+++ b/t/op/tie.t
@@ -1072,3 +1072,29 @@ tiehandle
before print
print()
Can't find label FOO at - line 4.
+########
+
+# \&$tied with $tied holding a reference before the fetch (but not after)
+sub ::72 { 73 };
+sub TIESCALAR {bless[]}
+sub STORE{}
+sub FETCH { 72 }
+tie my $x, "main";
+$x = \$y;
+\&$x;
+print "ok\n";
+EXPECT
+ok
+########
+
+# \&$tied with $tied holding a PVLV glob before the fetch (but not after)
+sub ::72 { 73 };
+sub TIEARRAY {bless[]}
+sub STORE{}
+sub FETCH { 72 }
+tie my @x, "main";
+my $elem = \$x[0];
+$$elem = *bar;
+print &{\&$$elem}, "\n";
+EXPECT
+73