summaryrefslogtreecommitdiff
path: root/t/base
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2015-05-05 10:44:16 +0100
committerDavid Mitchell <davem@iabyn.com>2015-05-05 11:23:36 +0100
commitde0885da327045eed274d7f8913a58e6de0e0f30 (patch)
treedbc5f111ef7848f03374934c460053f8fb25e603 /t/base
parentb12396ac84cef7e23e1aac516fa676165ddfc790 (diff)
downloadperl-de0885da327045eed274d7f8913a58e6de0e0f30.tar.gz
null ptr deref in Perl_cv_forget_slab
RT #124385 Parsing following a syntax error could result in a null ptr dereference. This commit contains a band-aid that returns from Perl_cv_forget_slab() if the cv arg is null; but the real issue is much deeper and needs a more general fix at some point. Basically, both the lexer and the parser use the save stack, and after an error, they can get out of sync. In particular: 1) when handling a double-quoted string, the lexer does an ENTER, saves most of its current state on the save stack, then uses the literal string as the toke source. When it reaches the end of the string, it LEAVEs, restores the lexer state and continues with the main source. 2) Whenever the parser starts a new block or sub scope, it remembers the current save stack position, and at end of scope, pops the save stack back to that position. In something like "@{ sub {]}} }}}" the lexer sees a double-quoted string, and saves the current lex state. The parser sees the start of a sub, and saves PL_compcv etc. Then a parse error occurs. The parser goes into error recovery, discarding tokens until it can return to a sane state. The lexer runs out of tokens when toking the string, does a LEAVE, and switches back to toking the main source. This LEAVE restores both the lexer's and the parser's state; in particular the parser gets its old PL_compcv restored, even though the parser hasn't finished compiling the current sub. Later, series of '}' tokens coming through allows the parser to finish the sub. Since PL_error_count > 0, it discards the just-compiled sub and sets PL_compcv to null. Normally the LEAVE_SCOPE done just after this would restore PL_compcv to its old value (e.g. PL_main_cv) but the stack has already been popped, so PL_compcv gets left null, and SEGVs occur. The two main ways I can think of fixing this in the long term are 1) avoid the lexer using the save stack for long-term state storage; in particular, make S_sublex_push() malloc a new parser object rather than saving the current lexer state on the save stack. 2) At the end of a sublex, if PL_error_count > 0, don't try to restore state and continue, instead just croak. N.B. the test that this commit adds to lex.t doesn't actually trigger the SEGV, since the bad code is wrapped in an eval which (for reasons I haven't researched) avoids the SEGV.
Diffstat (limited to 't/base')
-rw-r--r--t/base/lex.t8
1 files changed, 7 insertions, 1 deletions
diff --git a/t/base/lex.t b/t/base/lex.t
index a34a508653..8862337464 100644
--- a/t/base/lex.t
+++ b/t/base/lex.t
@@ -1,6 +1,6 @@
#!./perl
-print "1..102\n";
+print "1..103\n";
$x = 'x';
@@ -511,3 +511,9 @@ eval q|s##[}#e|;
# Used to crash [perl #124187]
eval q|qq{@{[{}}*sub{]]}}}=u|;
}
+
+{
+ # Used to crash [perl #124385]
+ eval '0; qq{@{sub{]]}}}}}';
+ print "ok $test - 124385\n"; $test++;
+}