diff options
author | David Mitchell <davem@iabyn.com> | 2014-05-02 13:51:00 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2014-05-02 13:56:20 +0100 |
commit | fc9668ae737de7993bbd27aa5c3eaddf41c5c885 (patch) | |
tree | 03fd7fdca31125b7c66d5f7cb5b945c3d0868f23 /t/op | |
parent | 70c5bd909f9ac3bc4de89d30e73693f3d07ea794 (diff) | |
download | perl-fc9668ae737de7993bbd27aa5c3eaddf41c5c885.tar.gz |
vec(): downgrade before accessing string buffer
This code:
#!perl -l
$x = substr "\x{100}\xff\xfe", 1;
print vec($x, 0, 8);
print vec($x, 0, 8);
In 5.18 and earlier prints
255
255
With blead it prints:
195
255
This is due to the fact that it does SvPV() first to get the string buffer,
then calls sv_utf8_downgrade(). With COW, the PVX of the SV may no longer
equal the value earlier returned by SvPV(), but vec() continues to use the
old pointer. This bug has always been present, but COW made it more
noticeable.
The fix is to just redo the SvPV() after a downgrade.
Diffstat (limited to 't/op')
-rw-r--r-- | t/op/vec.t | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/t/op/vec.t b/t/op/vec.t index b4afcf9cb8..30badb0138 100644 --- a/t/op/vec.t +++ b/t/op/vec.t @@ -6,7 +6,7 @@ BEGIN { } require "test.pl"; -plan( tests => 33 ); +plan( tests => 35 ); my $Is_EBCDIC = (ord('A') == 193) ? 1 : 0; @@ -112,3 +112,19 @@ use constant roref => \1; eval { for (roref) { vec($_,0,1) = 1 } }; like($@, qr/^Modification of a read-only value attempted at /, 'err msg when modifying read-only refs'); + + +{ + # downgradeable utf8 strings should be downgraded before accessing + # the byte string. + # See the p5p thread with Message-ID: + # <CAMx+QJ6SAv05nmpnc7bmp0Wo+sjcx=ssxCcE-P_PZ8HDuCQd9A@mail.gmail.com> + + + my $x = substr "\x{100}\xff\xfe", 1; # a utf8 string with all ords < 256 + my $v; + $v = vec($x, 0, 8); + is($v, 255, "downgraded utf8 try 1"); + $v = vec($x, 0, 8); + is($v, 255, "downgraded utf8 try 2"); +} |