diff options
author | David Mitchell <davem@iabyn.com> | 2015-05-05 10:44:16 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2015-05-05 11:23:36 +0100 |
commit | de0885da327045eed274d7f8913a58e6de0e0f30 (patch) | |
tree | dbc5f111ef7848f03374934c460053f8fb25e603 /t/base | |
parent | b12396ac84cef7e23e1aac516fa676165ddfc790 (diff) | |
download | perl-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.t | 8 |
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++; +} |