diff options
author | Yves Orton <demerphq@gmail.com> | 2022-08-26 18:26:14 +0200 |
---|---|---|
committer | Yves Orton <demerphq@gmail.com> | 2022-09-09 18:48:52 +0200 |
commit | eb54d46f7264ff7af62c409d8a6ab984a5a34f57 (patch) | |
tree | 87c90a0747b065f8994c54d569cb1b50eb7ae09b /toke.c | |
parent | 14580ae6b927552985b6b6294f9e836df39d0b65 (diff) | |
download | perl-eb54d46f7264ff7af62c409d8a6ab984a5a34f57.tar.gz |
Stop parsing on first syntax error.
We try to keep parsing after many types of errors, up to a (current)
maximum of 10 errors. Continuing after a semantic error (like
undeclared variables) can be helpful, for instance showing a set of
common errors, but continuing after a syntax error isn't helpful
most of the time as the internal state of the parser can get confused
and is not reliably restored in between attempts. This can produce
sometimes completely bizarre errors which just obscure the true error,
and has resulted in security tickets being filed in the past.
This patch makes the parser stop after the first syntax error, while
preserving the current behavior for other errors. An error is considered
a syntax error if the error message from our internals is the literal
text "syntax error". This may not be a complete list of true syntax
errors, we can iterate on that in the future.
This fixes the segfaults reported in Issue #17397, and #16944 and
likely fixes other "segfault due to compiler continuation after syntax
error" bugs that we have on record, which has been a recurring issue
over the years.
Diffstat (limited to 'toke.c')
-rw-r--r-- | toke.c | 56 |
1 files changed, 41 insertions, 15 deletions
@@ -12521,15 +12521,24 @@ S_yywarn(pTHX_ const char *const s, U32 flags) } void -Perl_abort_execution(pTHX_ const char * const msg, const char * const name) +Perl_abort_execution(pTHX_ SV* msg_sv, const char * const name) { PERL_ARGS_ASSERT_ABORT_EXECUTION; - if (PL_minus_c) - Perl_croak(aTHX_ "%s%s had compilation errors.\n", msg, name); - else { - Perl_croak(aTHX_ - "%sExecution of %s aborted due to compilation errors.\n", msg, name); + if (msg_sv) { + if (PL_minus_c) + Perl_croak(aTHX_ "%" SVf "%s had compilation errors.\n", SVfARG(msg_sv), name); + else { + Perl_croak(aTHX_ + "%" SVf "Execution of %s aborted due to compilation errors.\n", SVfARG(msg_sv), name); + } + } else { + if (PL_minus_c) + Perl_croak(aTHX_ "%s had compilation errors.\n", name); + else { + Perl_croak(aTHX_ + "Execution of %s aborted due to compilation errors.\n", name); + } } NOT_REACHED; /* NOTREACHED */ } @@ -12644,22 +12653,39 @@ Perl_yyerror_pvn(pTHX_ const char *const s, STRLEN len, U32 flags) qerror(msg); } } - if (s == NULL || PL_error_count >= 10) { - const char * msg = ""; + if ( s == NULL || + PL_error_count >= PERL_STOP_PARSING_AFTER_N_ERRORS + ) { const char * const name = OutCopFILE(PL_curcop); + SV * errsv = NULL; + U8 raw_error_count = PERL_PARSE_ERROR_COUNT(PL_error_count); + bool syntax_error = PERL_PARSE_IS_SYNTAX_ERROR(PL_error_count); if (PL_in_eval) { - SV * errsv = ERRSV; - if (SvCUR(errsv)) { - msg = Perl_form(aTHX_ "%" SVf, SVfARG(errsv)); - } + errsv = ERRSV; } if (s == NULL) { - abort_execution(msg, name); + abort_execution(errsv, name); } - else { - Perl_croak(aTHX_ "%s%s has too many errors.\n", msg, name); + else + if (raw_error_count >= PERL_STOP_PARSING_AFTER_N_ERRORS) { + if (errsv) { + Perl_croak(aTHX_ "%" SVf "%s has too many errors.\n", + SVfARG(errsv), name); + } else { + Perl_croak(aTHX_ "%s has too many errors.\n", name); + } + } + else + /* if (syntax_error) - implied */ + { + assert(syntax_error); + if (errsv) { + Perl_croak_sv(aTHX_ errsv); + } else { + abort_execution(errsv, name); + } } } PL_in_my = 0; |