This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #79178] STORE/FETCH of tie()d hash get stringified key
authorFather Chrysostomos <sprout@cpan.org>
Sat, 27 Nov 2010 14:22:24 +0000 (06:22 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Sat, 27 Nov 2010 15:15:35 +0000 (07:15 -0800)
This bug has been present in non-threaded builds for a long time.
Change 38bb37b9aa introduced it to threaded builds.

$hash{...} makes its operand a shared-PV scalar if it is an OP_CONST.
But \"foo" is also an OP_CONST, as is anything generated with use
constant. This is the sort of thing that results:

$ perl5.8.5 -MO=Concise -e '$a{\"foo"}'
7  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v ->3
6     <2> helem vK/2 ->7
4        <1> rv2hv sKR/1 ->5
3           <$> gv(*a) s ->4
5        <$> const(PVIV "SCALAR(0x81b378)") s ->6
-e syntax OK

(My 5.8.5 installation is non-threaded.)

See the "SCALAR(0x81b378)" in there?

So this commit skips that optimisation if the key is ROK or if it is a
PVMG or higher.

op.c
t/op/hash.t

diff --git a/op.c b/op.c
index 53641c7..4c3c876 100644 (file)
--- a/op.c
+++ b/op.c
@@ -9661,7 +9661,8 @@ Perl_rpeep(pTHX_ register OP *o)
 
            /* Make the CONST have a shared SV */
            svp = cSVOPx_svp(((BINOP*)o)->op_last);
-           if (!SvFAKE(sv = *svp) || !SvREADONLY(sv)) {
+           if ((!SvFAKE(sv = *svp) || !SvREADONLY(sv))
+            && SvTYPE(sv) < SVt_PVMG && !SvROK(sv)) {
                key = SvPV_const(sv, keylen);
                lexname = newSVpvn_share(key,
                                         SvUTF8(sv) ? -(I32)keylen : (I32)keylen,
index d75d059..fe8a856 100644 (file)
@@ -8,7 +8,7 @@ BEGIN {
 
 use strict;
 
-plan tests => 7;
+plan tests => 8;
 
 my %h;
 
@@ -130,3 +130,19 @@ $destroyed = 0;
     $h{key} = bless({}, 'Class');
 }
 is($destroyed, 1, 'Timely hash destruction with lvalue keys');
+
+
+# [perl #79178] Hash keys must not be stringified during compilation
+# Run perl -MO=Concise -e '$a{\"foo"}' on a non-threaded pre-5.13.8 version
+# to see why.
+{
+    my $key;
+    package bar;
+    sub TIEHASH { bless {}, $_[0] }
+    sub FETCH { $key = $_[1] }
+    package main;
+    tie my %h, "bar";
+    $h{\'foo'};
+    is ref $key, SCALAR =>
+     'hash keys are not stringified during compilation';
+}