[RT #78266] Don't leak memory when accessing named captures that didn't match
authorÆvar Arnfjörð Bjarmason <avar@cpan.org>
Tue, 13 Dec 2011 14:43:12 +0000 (14:43 +0000)
committerÆvar Arnfjörð Bjarmason <avar@cpan.org>
Tue, 13 Dec 2011 18:08:57 +0000 (18:08 +0000)
Since 5.10 (probably 44a2ac759e) named captures have been leaking
memory when they're used, don't actually match, but are later
accessed. E.g.:

    $ perl -wle 'for (1..10_000_000) { if ("foo" =~ /(foo|(?<capture>bar))?/) { my $capture = $+{capture} } } system "ps -o rss $$"'
      RSS
    238524

Here we match the "foo" branch of our regex, but since we've used a
name capture we'll end up running the code in
Perl_reg_named_buff_fetch, which allocates a newSVsv(&PL_sv_undef) but
never uses it unless it's trying to return an array.

Just change that code not to allocate scalars we don't plan to
return. With this fix we don't leak any memory since there's nothing
to leak anymore.

    $ ./perl -Ilib -wle 'for (1..10_000_000) { if ("foo" =~ /(foo|(?<capture>bar))?/) { my $capture = $+{capture} } } system "ps -o rss $$"'
      RSS
     3528

This reverts commit b28f4af8cf94eb18c0cfde71e9625081912499a8 ("Fix
allocating something in the first place is a better solution than
allocating it, not using it, and then freeing it.

pod/perldelta.pod
regcomp.c

index 22ecd27..7f65ef6 100644 (file)
@@ -589,6 +589,15 @@ L</Modules and Pragmata>.
 
 =item *
 
+RT #78266: The regex engine has been leaking memory when accessing
+named captures that weren't matched as part of a regex ever since 5.10
+when they were introduced, e.g. this would consume over a hundred MB
+of memory:
+
+    perl -wle 'for (1..10_000_000) { if ("foo" =~ /(foo|(?<capture>bar))?/) { my $capture = $+{capture} } } system "ps -o rss $$"'
+
+=item *
+
 A constant subroutine assigned to a glob whose name contains a null will no
 longer cause extra globs to pop into existence when the constant is
 referenced under its new name.
index 9e9fac4..56b2b9c 100644 (file)
--- a/regcomp.c
+++ b/regcomp.c
@@ -5409,7 +5409,8 @@ Perl_reg_named_buff_fetch(pTHX_ REGEXP * const r, SV * const namesv,
                     if (!retarray)
                         return ret;
                 } else {
-                    ret = newSVsv(&PL_sv_undef);
+                    if (retarray)
+                        ret = newSVsv(&PL_sv_undef);
                 }
                 if (retarray)
                     av_push(retarray, ret);
@@ -5418,10 +5419,6 @@ Perl_reg_named_buff_fetch(pTHX_ REGEXP * const r, SV * const namesv,
                 return newRV_noinc(MUTABLE_SV(retarray));
         }
     }
-
-    if (ret)
-        SvREFCNT_dec(ret);
-
     return NULL;
 }