Make pos less volatile when UTF8-ness can change
authorFather Chrysostomos <sprout@cpan.org>
Wed, 26 Sep 2012 03:33:30 +0000 (20:33 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Mon, 1 Oct 2012 19:51:50 +0000 (12:51 -0700)
This was brought up in ticket #114690.

pos checks the length of the string and then its UTF8-ness.  But the
UTF8-ness is not updated by length magic.  So it can get confused if
simply stringifying a match var happens to flip the UTF8 flag:

$ perl -le '"\x{100}a" =~ /(..)/; pos($1) = 2; print pos($1); "$1";
print pos($1)'
2
1

$ perl -le '"\x{100}a" =~ /(.)/; pos($1) = 2; print pos($1); "$1"; print
pos($1)'
1
Malformed UTF-8 character (unexpected end of string) in match position
at -e line 1.
0

As pointed out in that ticket, length magic on scalars cannot work
properly with UTF8, so stop using it.

sv.c
t/op/pos.t

index 2417e86..67d3ed9 100644 (file)
--- a/sv.c
+++ b/sv.c
@@ -6485,10 +6485,7 @@ Perl_sv_len(pTHX_ register SV *const sv)
     if (!sv)
        return 0;
 
-    if (SvGMAGICAL(sv))
-       len = mg_length(sv);
-    else
-        (void)SvPV_const(sv, len);
+    (void)SvPV_const(sv, len);
     return len;
 }
 
index 67de5d4..40a91f6 100644 (file)
@@ -6,7 +6,7 @@ BEGIN {
     require './test.pl';
 }
 
-plan tests => 11;
+plan tests => 12;
 
 $x='banana';
 $x=~/.a/g;
@@ -56,3 +56,10 @@ like $@, qr/^Can't modify hash dereference in match position at /,
   'pos refuses %hashes';
 eval 'pos *a = 1';
 is eval 'pos *a', 1, 'pos *glob works';
+
+# Test that UTF8-ness of $1 changing does not confuse pos
+"f" =~ /(f)/; "$1";    # first make sure UTF8-ness is off
+"\x{100}a" =~ /(..)/;  # give PL_curpm a UTF8 string; $1 does not know yet
+pos($1) = 2;           # set pos; was ignoring UTF8-ness
+"$1";                  # turn on UTF8 flag
+is pos($1), 2, 'pos is not confused about changing UTF8-ness';