In perl.git, the branch smoke-me/nicholas/rt-65838-fixup has been updated <http://perl5.git.perl.org/perl.git/commitdiff/78a9cd0fe99ca35bb2a4ffe8640c44e4e25bc995?hp=ec79994d178a58009af5b2b0b22e1d93a4787c7a>
- Log ----------------------------------------------------------------- commit 78a9cd0fe99ca35bb2a4ffe8640c44e4e25bc995 Author: Nicholas Clark <n...@ccl4.org> Date: Thu Jun 27 18:09:32 2013 +0200 Avoid read-after-free in S_scan_heredoc() if the terminator line has no "\n". The code added by commit 112d128413206514 to fix RT #65838 (Allow here-doc with no final newline) could in some rare cases cause a read of free()d memory during parsing. The code itself is only run if the Perl program ends with a heredoc (which is an unusual structure), and if the last line of the file on disk has terminating newline character (which is also unusual, as many editors default to adding a final newline). The bug would be triggered if the fixup code in S_scan_heredoc() triggered a reallocation of the buffer in PL_linestr when adding a newline to it. ----------------------------------------------------------------------- Summary of changes: t/op/heredoc.t | 21 ++++++++++++++------- toke.c | 3 ++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/t/op/heredoc.t b/t/op/heredoc.t index 08b0af2..55a19f0 100644 --- a/t/op/heredoc.t +++ b/t/op/heredoc.t @@ -7,7 +7,7 @@ BEGIN { } use strict; -plan(tests => 9); +plan(tests => 39); # heredoc without newline (#65838) @@ -69,12 +69,19 @@ HEREDOC "string terminator must start at newline" ); - fresh_perl_like( - "print <<;\nno more newlines", - qr/find string terminator/, - { switches => ['-X'] }, - "empty string terminator still needs a newline" - ); + # Loop over various lengths to try to force at least one to cause a + # reallocation in S_scan_heredoc() + # Timing on a modern machine suggests that this loop executes in less than + # 0.1s, so it's a very small cost for the default build. The benefit is + # that building with ASAN will reveal the bug and any related regressions. + for (1..31) { + fresh_perl_like( + "print <<;\n" . "x" x $_, + qr/find string terminator/, + { switches => ['-X'] }, + "empty string terminator still needs a newline (length $_)" + ); + } fresh_perl_like( "print <<ThisTerminatorIsLongerThanTheData;\nno more newlines", diff --git a/toke.c b/toke.c index aedccc5..f9c9937 100644 --- a/toke.c +++ b/toke.c @@ -10115,8 +10115,9 @@ S_scan_heredoc(pTHX_ char *s) } CopLINE_set(PL_curcop, (line_t)PL_multi_start - 1); if (!SvCUR(PL_linestr) || PL_bufend[-1] != '\n') { - lex_grow_linestr(SvCUR(PL_linestr) + 2); + s = lex_grow_linestr(SvLEN(PL_linestr) + 3); sv_catpvs(PL_linestr, "\n\0"); + PL_bufend = SvEND(PL_linestr); } s = PL_bufptr; #ifdef PERL_MAD -- Perl5 Master Repository