In perl.git, the branch blead has been updated <https://perl5.git.perl.org/perl.git/commitdiff/bb4e4c3869d9fb6ee5bddd820c2a373601ecc310?hp=4bfb5532d393d56b18d13bc19f70f6f7a64ae781>
- Log ----------------------------------------------------------------- commit bb4e4c3869d9fb6ee5bddd820c2a373601ecc310 Author: Tony Cook <t...@develop-help.com> Date: Tue Jan 30 16:40:53 2018 +1100 (perl #125351) abort parsing if parse errors happen in a sub lex We've had a few reports of segmentation faults and other misbehaviour when sub-parsing, such as within interpolated expressions, fails. This change aborts compilation if anything complex enough to not be parsed by the lexer is compiled in a sub-parse *and* an error occurs within the sub-parse. An earlier version of this patch failed on simpler expressions, which caused many test failures, which this version doesn't (which may just mean we need more tests...) ----------------------------------------------------------------------- Summary of changes: parser.h | 2 ++ t/base/lex.t | 11 ++++++++++- toke.c | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/parser.h b/parser.h index 4187e0a93d..216e9deca8 100644 --- a/parser.h +++ b/parser.h @@ -58,6 +58,7 @@ typedef struct yy_parser { 1 = @{...} 2 = ->@ */ U8 expect; /* how to interpret ambiguous tokens */ bool preambled; + bool sub_no_recover; /* can't recover from a sublex error */ I32 lex_formbrack; /* bracket count at outer format level */ OP *lex_inpat; /* in pattern $) and $| are special */ OP *lex_op; /* extra info to pass back on op */ @@ -95,6 +96,7 @@ typedef struct yy_parser { U16 in_my; /* we're compiling a "my"/"our" declaration */ U8 lex_state; /* next token is determined */ U8 error_count; /* how many compile errors so far, max 10 */ + U8 sub_error_count; /* the number of errors before sublexing */ HV *in_my_stash; /* declared class of this "my" declaration */ PerlIO *rsfp; /* current source file pointer */ AV *rsfp_filters; /* holds chain of active source filters */ diff --git a/t/base/lex.t b/t/base/lex.t index de33e7a688..414aa1fceb 100644 --- a/t/base/lex.t +++ b/t/base/lex.t @@ -1,6 +1,6 @@ #!./perl -print "1..117\n"; +print "1..120\n"; $x = 'x'; @@ -557,6 +557,15 @@ eval q|s##[}#e|; eval ('/@0{0*->@*/*]'); print "ok $test - 128171\n"; $test++; } +{ + # various sub-parse recovery issues that crashed perl + eval 's//${sub{b{]]]{}#$/ sub{}'; + print "ok $test - 132640\n"; $test++; + eval 'qq{@{sub{]]}}}};shift'; + print "ok $test - 125351\n"; $test++; + eval 'qq{@{sub{]]}}}}-shift'; + print "ok $test - 126192\n"; $test++; +} $foo = "WRONG"; $foo:: = "bar"; $bar = "baz"; print "not " unless "$foo::$bar" eq "barbaz"; diff --git a/toke.c b/toke.c index 4e0c3c3189..9f37f53ba4 100644 --- a/toke.c +++ b/toke.c @@ -2390,6 +2390,8 @@ S_sublex_start(pTHX) PL_parser->lex_super_state = PL_lex_state; PL_parser->lex_sub_inwhat = (U16)op_type; PL_parser->lex_sub_op = PL_lex_op; + PL_parser->sub_no_recover = FALSE; + PL_parser->sub_error_count = PL_error_count; PL_lex_state = LEX_INTERPPUSH; PL_expect = XTERM; @@ -2569,6 +2571,20 @@ S_sublex_done(pTHX) else { const line_t l = CopLINE(PL_curcop); LEAVE; + if (PL_parser->sub_error_count != PL_error_count) { + const char * const name = OutCopFILE(PL_curcop); + if (PL_parser->sub_no_recover) { + const char * msg = ""; + if (PL_in_eval) { + SV *errsv = ERRSV; + if (SvCUR(ERRSV)) { + msg = Perl_form(aTHX_ "%" SVf, SVfARG(errsv)); + } + } + abort_execution(msg, name); + NOT_REACHED; + } + } if (PL_multi_close == '<') PL_parser->herelines += l - PL_multi_end; PL_bufend = SvPVX(PL_linestr); @@ -4157,6 +4173,7 @@ S_intuit_more(pTHX_ char *s, char *e) return TRUE; if (*s != '{' && *s != '[') return FALSE; + PL_parser->sub_no_recover = TRUE; if (!PL_lex_inpat) return TRUE; @@ -9580,6 +9597,7 @@ S_scan_ident(pTHX_ char *s, char *dest, STRLEN destlen, I32 ck_uni) CopLINE_set(PL_curcop, orig_copline); PL_parser->herelines = herelines; *dest = '\0'; + PL_parser->sub_no_recover = TRUE; } } else if ( PL_lex_state == LEX_INTERPNORMAL -- Perl5 Master Repository