This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
(perl #128997) avoid reading beyond the end of the line buffer
authorTony Cook <tony@develop-help.com>
Tue, 18 Oct 2016 04:46:48 +0000 (15:46 +1100)
committerTony Cook <tony@develop-help.com>
Mon, 31 Oct 2016 04:09:10 +0000 (15:09 +1100)
when there's a short UTF-8 character at the end.

t/op/lex.t
toke.c

index db0cf3a..f3cb510 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 
 BEGIN { chdir 't' if -d 't'; require './test.pl'; }
 
-plan(tests => 32);
+plan(tests => 33);
 
 {
     no warnings 'deprecated';
@@ -255,3 +255,9 @@ fresh_perl_is(
     {},
     '[perl #128996] - use of PL_op after op is freed'
 );
+fresh_perl_like(
+    qq(BEGIN{\$0="";\$^H=-hex join""=>1}""\xFF),
+    qr/Malformed UTF-8 character: \\xff \(too short; got 1 byte, need 13\) at - line 1\./,
+    {},
+    '[perl #128997] - buffer read overflow'
+);
diff --git a/toke.c b/toke.c
index b2d9209..ffac930 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -4901,11 +4901,18 @@ Perl_yylex(pTHX)
        }
     {
         SV *dsv = newSVpvs_flags("", SVs_TEMP);
-        const char *c = UTF ? sv_uni_display(dsv, newSVpvn_flags(s,
-                                                    UTF8SKIP(s),
-                                                    SVs_TEMP | SVf_UTF8),
-                                            10, UNI_DISPLAY_ISPRINT)
-                            : Perl_form(aTHX_ "\\x%02X", (unsigned char)*s);
+        const char *c;
+        if (UTF) {
+            STRLEN skiplen = UTF8SKIP(s);
+            STRLEN stravail = PL_bufend - s;
+            c = sv_uni_display(dsv, newSVpvn_flags(s,
+                                                   skiplen > stravail ? stravail : skiplen,
+                                                   SVs_TEMP | SVf_UTF8),
+                               10, UNI_DISPLAY_ISPRINT);
+        }
+        else {
+            c = Perl_form(aTHX_ "\\x%02X", (unsigned char)*s);
+        }
         len = UTF ? Perl_utf8_length(aTHX_ (U8 *) PL_linestart, (U8 *) s) : (STRLEN) (s - PL_linestart);
         if (len > UNRECOGNIZED_PRECEDE_COUNT) {
             d = UTF ? (char *) utf8_hop((U8 *) s, -UNRECOGNIZED_PRECEDE_COUNT) : s - UNRECOGNIZED_PRECEDE_COUNT;