Don’t leak pattern buffer when invalid flags croak
authorFather Chrysostomos <sprout@cpan.org>
Sun, 4 Nov 2012 07:03:43 +0000 (00:03 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Mon, 5 Nov 2012 06:45:33 +0000 (22:45 -0800)
Normally if there is a syntax error yyerror just records it and pars-
ing continues anyway.  If there are too many syntax errors, it croaks.

It just happened that if it croaked when encountering invalid flags
for quote-like operators it would leak the buffer containing the pat-
tern (and the substitution for s///).

Since those are stored in the parser struct and are set to null when-
ever something else takes ownership of the SV, these struct members
will only ever be non-null in parser_free when they have leaked.  So
we can free them there.  (I.e., these slots have always been refer-
ence-counted, so treat them that way.)

t/op/svleak.t
toke.c

index ee646d7..dfb1886 100644 (file)
@@ -15,7 +15,7 @@ BEGIN {
 
 use Config;
 
-plan tests => 50;
+plan tests => 52;
 
 # run some code N times. If the number of SVs at the end of loop N is
 # greater than (N-1)*delta at the end of loop 1, we've got a leak
@@ -195,6 +195,8 @@ eleak(2, 0, 'tr/9-0//');
 eleak(2, 0, 'tr/a-z-0//');
 eleak(2, 0, 'no warnings; nonexistent_function 33838',
         'bareword followed by number');
+eleak(2, 0, '//dd;'x20, '"too many errors" when parsing m// flags');
+eleak(2, 0, 's///dd;'x20, '"too many errors" when parsing s/// flags');
 
 # [perl #114764] Attributes leak scalars
 leak(2, 0, sub { eval 'my $x : shared' }, 'my $x :shared used to leak');
diff --git a/toke.c b/toke.c
index 46ad0a4..0d00d9e 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -784,6 +784,8 @@ Perl_parser_free(pTHX_  const yy_parser *parser)
                (parser->old_parser && parser->rsfp != parser->old_parser->rsfp)))
        PerlIO_close(parser->rsfp);
     SvREFCNT_dec(parser->rsfp_filters);
+    SvREFCNT_dec(parser->lex_stuff);
+    SvREFCNT_dec(parser->sublex_info.repl);
 
     Safefree(parser->lex_brackstack);
     Safefree(parser->lex_casestack);