diff options
author | David Mitchell <davem@iabyn.com> | 2010-04-25 16:28:41 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2010-04-25 16:39:58 +0100 |
commit | 39cf747a86645fde6898cd6d09d351d50755c2fa (patch) | |
tree | ca3f0f3f8ba67fd92e04fd7ff7e8ed4dec137852 | |
parent | 529f008e1350d1b04e9f98427e8b2c8717a80712 (diff) | |
download | perl-39cf747a86645fde6898cd6d09d351d50755c2fa.tar.gz |
avoid multiple FETCHes
The fix 2d961f6deff7 for RT #5475 included a mechanism for the early
calling of get magic on something like
$tied[0];
so that even though the element is used in void context, we still call
FETCH. Some people seem to rely on this.
However, the call to mg_get() didn't distinguish between a tiedelem
member retrieved from a tied array/hash, and a tiedscalar element
retrieved from a plain array/hash. In the latter case, the S_GSKIP
protection mechanism doesn't apply and a simple $foo = $h{tiedelem}
generated two calls to FETCH.
Fix this by only calling mg_get() on the element if it came from a *tied*
array/hash.
A side-effect of this fix is that the following no longer calls FETCH:
my @plain_array;
tie $plain_array[0], ....; # element 0 is now a tied scalar
$plain_array[0]; # void context: no longer calls FETCH.
This required one test in op/tie.t to be fixed up, but in general I think
this is a reasonable compromise.
-rw-r--r-- | pp_hot.c | 6 | ||||
-rw-r--r-- | t/op/tie.t | 24 |
2 files changed, 26 insertions, 4 deletions
@@ -663,7 +663,7 @@ PP(pp_aelemfast) SV** const svp = av_fetch(av, PL_op->op_private, lval); SV *sv = (svp ? *svp : &PL_sv_undef); EXTEND(SP, 1); - if (!lval && SvGMAGICAL(sv)) /* see note in pp_helem() */ + if (!lval && SvRMAGICAL(av) && SvGMAGICAL(sv)) /* see note in pp_helem() */ mg_get(sv); PUSHs(sv); RETURN; @@ -1858,7 +1858,7 @@ PP(pp_helem) * meant the original regex may be out of scope by now. So as a * compromise, do the get magic here. (The MGf_GSKIP flag will stop it * being called too many times). */ - if (!lval && SvGMAGICAL(sv)) + if (!lval && SvRMAGICAL(hv) && SvGMAGICAL(sv)) mg_get(sv); PUSHs(sv); RETURN; @@ -2996,7 +2996,7 @@ PP(pp_aelem) vivify_ref(*svp, PL_op->op_private & OPpDEREF); } sv = (svp ? *svp : &PL_sv_undef); - if (!lval && SvGMAGICAL(sv)) /* see note in pp_helem() */ + if (!lval && SvRMAGICAL(av) && SvGMAGICAL(sv)) /* see note in pp_helem() */ mg_get(sv); PUSHs(sv); RETURN; diff --git a/t/op/tie.t b/t/op/tie.t index 2ef710167f..bd3f2e50f7 100644 --- a/t/op/tie.t +++ b/t/op/tie.t @@ -337,7 +337,7 @@ sub FETCH { } package main; tie $a->{foo}, "Foo", $a, "foo"; -$a->{foo}; # access once +my $s = $a->{foo}; # access once # the hash element should not be tied anymore print defined tied $a->{foo} ? "not ok" : "ok"; EXPECT @@ -768,3 +768,25 @@ foreach ($a[0], $h{a}) { } # on failure, chucks up 'premature free' etc messages EXPECT +######## +# RT 5475: +# the initial fix for this bug caused tied scalar FETCH to be called +# multiple times when that scalar was an element in an array. Check it +# only gets called once now. + +sub TIESCALAR { bless [], $_[0] } +my $c = 0; +sub FETCH { $c++; 0 } +sub FETCHSIZE { 1 } +sub STORE { $c += 100; 0 } + + +my (@a, %h); +tie $a[0], 'main'; +tie $h{foo}, 'main'; + +my $i = 0; +my $x = $a[0] + $h{foo} + $a[$i] + (@a)[0]; +print "x=$x c=$c\n"; +EXPECT +x=0 c=4 |