Blob Blame History Raw
From cfb736762c1becf344ce6beaa701ff2e1abd5f9c Mon Sep 17 00:00:00 2001
From: Yves Orton <demerphq@gmail.com>
Date: Tue, 13 Sep 2016 23:14:49 +0200
Subject: [PATCH 4/5] fix #129267: rework gv_fetchmethod_pvn_flags separator
 parsing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

With previous code we could overrun the end of the name when
the last char in the string was a colon. This reworks the code
so it is more clear what is going on, and so it more similar
to other code that also parses out package separaters in gv.c.

This is a rework of the reverted patches:
243ca72 rename "nend" name_cursor in Perl_gv_fetchmethod_pvn_flags
b053c93 fix: [perl #129267] Possible string overrun with invalid len in gv.c

Signed-off-by: Petr Písař <ppisar@redhat.com>
---
 gv.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/gv.c b/gv.c
index 07709a0..3237c53 100644
--- a/gv.c
+++ b/gv.c
@@ -1010,7 +1010,6 @@ Perl_gv_fetchmethod_pvn_flags(pTHX_ HV *stash, const char *name, const STRLEN le
 {
     const char * const origname = name;
     const char * const name_end = name + len;
-    const char *nend;
     const char *last_separator = NULL;
     GV* gv;
     HV* ostash = stash;
@@ -1029,16 +1028,33 @@ Perl_gv_fetchmethod_pvn_flags(pTHX_ HV *stash, const char *name, const STRLEN le
 	   the error reporting code.  */
     }
 
-    for (nend = name; *nend || nend != name_end; nend++) {
-	if (*nend == '\'') {
-	    last_separator = nend;
-	    name = nend + 1;
-	}
-	else if (*nend == ':' && *(nend + 1) == ':') {
-	    last_separator = nend++;
-	    name = nend + 1;
-	}
+    {
+        /* check if the method name is fully qualified or
+         * not, and separate the package name from the actual
+         * method name.
+         *
+         * leaves last_separator pointing to the beginning of the
+         * last package separator (either ' or ::) or 0
+         * if none was found.
+         *
+         * leaves name pointing at the beginning of the
+         * method name.
+         */
+        const char *name_cursor = name;
+        const char * const name_em1 = name_end - 1; /* name_end minus 1 */
+        for (name_cursor = name; name_cursor < name_end ; name_cursor++) {
+            if (*name_cursor == '\'') {
+                last_separator = name_cursor;
+                name = name_cursor + 1;
+            }
+            else if (name_cursor < name_em1 && *name_cursor == ':' && name_cursor[1] == ':') {
+                last_separator = name_cursor++;
+                name = name_cursor + 1;
+            }
+        }
     }
+
+    /* did we find a separator? */
     if (last_separator) {
 	if ((last_separator - origname) == 5 && memEQ(origname, "SUPER", 5)) {
 	    /* ->SUPER::method should really be looked up in original stash */
-- 
2.7.4