diff options
author | David Mitchell <davem@iabyn.com> | 2015-04-15 08:47:18 +0100 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2015-04-15 08:47:18 +0100 |
commit | c7f317a9270a52c9028667b8adec18e94f450586 (patch) | |
tree | 836eab4f0534a79f8c51fa6aa8e9e0b8fee5b097 /toke.c | |
parent | 2c0445268a1bb7696e04b8b9b324c3d6880bb18a (diff) | |
download | perl-c7f317a9270a52c9028667b8adec18e94f450586.tar.gz |
assertion failure on interpolated parse err
RT# 124216
When paring the interpolated string "$X", where X is a unicode char that
is not a legal variable name, failure to restore things properly during
error recovery led to corrupted state and assertion failures.
In more detail:
When parsing a double-quoted string, S_sublex_push() saves most of the
current parser state. On parse error, the save stack is popped back,
which restores all that state. However, PL_lex_defer wasn't being saved,
so if we were in the middle of handling a forced token, PL_lex_state gets
restored from PL_lex_defer, and suddenly the lexer thinks we're back
inside an interpolated string again. So S_sublex_done() gets called
multiple times, too many scopes are popped, and things like PL_compcv are
freed prematurely.
Note that in order to reproduce:
* we must be within a double quoted context;
* we must be parsing a var (which causes a forced token);
* the variable name must be illegal, which implies unicode, as
chr(0..255) are all legal names;
* the terminating string quote must be the last char of the input
file, as this code:
case LEX_INTERPSTART:
if (PL_bufptr == PL_bufend)
return REPORT(sublex_done());
won't trigger an extra call to sublex_done() otherwise.
I'm sure this bug affects other cases too, but this was the only way I
found to reproduce.
Diffstat (limited to 'toke.c')
-rw-r--r-- | toke.c | 1 |
1 files changed, 1 insertions, 0 deletions
@@ -2342,6 +2342,7 @@ S_sublex_push(pTHX) SAVEI32(PL_lex_casemods); SAVEI32(PL_lex_starts); SAVEI8(PL_lex_state); + SAVEI8(PL_lex_defer); SAVESPTR(PL_lex_repl); SAVEVPTR(PL_lex_inpat); SAVEI16(PL_lex_inwhat); |