78f1eb
From 89f69032d6a71f41b96ae6becbf3df4e2f9509a5 Mon Sep 17 00:00:00 2001
78f1eb
From: Karl Williamson <khw@cpan.org>
78f1eb
Date: Sat, 27 Apr 2019 13:56:39 -0600
78f1eb
Subject: [PATCH] S_scan_const() Properly test if need to grow
78f1eb
MIME-Version: 1.0
78f1eb
Content-Type: text/plain; charset=UTF-8
78f1eb
Content-Transfer-Encoding: 8bit
78f1eb
78f1eb
As we parse the input, creating a string constant, we may have to grow
78f1eb
the destination if it fills up as we go along.  It allocates space in an
78f1eb
SV and populates the string, but it doesn' update the SvCUR until the
78f1eb
end, so in single stepping the debugger through the code, the SV looks
78f1eb
empty until the end.  It turns out that as a result SvEND also doesn't
78f1eb
get updated and still points to the beginning of the string until SvCUR
78f1eb
is finally set.  That means that the test changed by this commit was
78f1eb
always succeeding, because it was using SvEND that didn't get updated,
78f1eb
so it would attempt to grow each time through the loop.  By moving a
78f1eb
couple of statements earlier, and using SvLEN instead, which does always
78f1eb
have the correct value, those extra growth attempts are avoided.
78f1eb
78f1eb
Signed-off-by: Petr Písař <ppisar@redhat.com>
78f1eb
---
78f1eb
 toke.c | 10 ++++++----
78f1eb
 1 file changed, 6 insertions(+), 4 deletions(-)
78f1eb
78f1eb
diff --git a/toke.c b/toke.c
78f1eb
index 68eea0cae6..03c4f2ba26 100644
78f1eb
--- a/toke.c
78f1eb
+++ b/toke.c
78f1eb
@@ -4097,10 +4097,12 @@ S_scan_const(pTHX_ char *start)
78f1eb
             goto default_action; /* Redo, having upgraded so both are UTF-8 */
78f1eb
         }
78f1eb
         else {  /* UTF8ness matters: convert this non-UTF8 source char to
78f1eb
-                   UTF-8 for output.  It will occupy 2 bytes */
78f1eb
-            if (d + 2 >= SvEND(sv)) {
78f1eb
-                const STRLEN extra = 2 + (send - s - 1) + 1;
78f1eb
-		const STRLEN off = d - SvPVX_const(sv);
78f1eb
+                   UTF-8 for output.  It will occupy 2 bytes, but don't include
78f1eb
+                   the input byte since we haven't incremented 's' yet. See
78f1eb
+                   Note on sizing above. */
78f1eb
+            const STRLEN off = d - SvPVX(sv);
78f1eb
+            const STRLEN extra = 2 + (send - s - 1) + 1;
78f1eb
+            if (off + extra > SvLEN(sv)) {
78f1eb
 		d = off + SvGROW(sv, off + extra);
78f1eb
 	    }
78f1eb
             *d++ = UTF8_EIGHT_BIT_HI(*s);
78f1eb
-- 
78f1eb
2.20.1
78f1eb