This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix leak in package name lookup
authorDavid Mitchell <davem@iabyn.com>
Tue, 26 Mar 2019 08:56:55 +0000 (08:56 +0000)
committerDavid Mitchell <davem@iabyn.com>
Tue, 26 Mar 2019 08:56:55 +0000 (08:56 +0000)
S_parse_gv_stash_name() mallocs a temporary buffer when scanning package
names longer than 64 bytes. Depending on how it exits the function, it
doesn't always free the buffer afterwards. Change the function so that
there are only two exit points (which free the buffer) and make other bits
of code goto those two points.

Can be reproduced with e.g.

&{"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'x"}

Similar code is already present in t/op/stash_parse_gv.t

gv.c

diff --git a/gv.c b/gv.c
index ae7f2aa..61085f5 100644 (file)
--- a/gv.c
+++ b/gv.c
@@ -1636,7 +1636,7 @@ S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name,
             if (!*stash)
                 *stash = PL_defstash;
             if (!*stash || !SvREFCNT(*stash)) /* symbol table under destruction */
-                return FALSE;
+                goto notok;
 
             *len = name_cursor - *name;
             if (name_cursor > nambeg) { /* Skip for initial :: or ' */
@@ -1666,7 +1666,7 @@ S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name,
                 *gv = gvp ? *gvp : NULL;
                 if (!*gv || *gv == (const GV *)&PL_sv_undef) {
                     Safefree(tmpfullbuf); /* free our tmpfullbuf if it was used */
-                    return FALSE;
+                    goto notok;
                 }
                 /* here we know that *gv && *gv != &PL_sv_undef */
                 if (SvTYPE(*gv) != SVt_PVGV)
@@ -1707,15 +1707,20 @@ S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name,
                            MUTABLE_HV(SvREFCNT_inc_simple(PL_defstash));
                    }
                }
-                Safefree(tmpfullbuf); /* free our tmpfullbuf if it was used */
-                return TRUE;
+                goto ok;
             }
         }
     }
     *len = name_cursor - *name;
+  ok:
+    Safefree(tmpfullbuf); /* free our tmpfullbuf if it was used */
     return TRUE;
+  notok:
+    Safefree(tmpfullbuf); /* free our tmpfullbuf if it was used */
+    return FALSE;
 }
 
+
 /* Checks if an unqualified name is in the main stash */
 PERL_STATIC_INLINE bool
 S_gv_is_in_main(pTHX_ const char *name, STRLEN len, const U32 is_utf8)