[parser] Check overflow in parser productions rather than token handling
Added to crucial productions that will incur in any infinite recursion: - In ParsePrimaryExpression - In all ParseUnaryExpression subrules - In ParseDoWhileStatement - In ParseBlock Change-Id: Iaee295eb5652e57712d029999b36078fea3b7dab Reviewed-on: https://chromium-review.googlesource.com/c/1290794 Reviewed-by: Camillo Bruni <cbruni@chromium.org> Commit-Queue: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#56816}
This commit is contained in:
parent
5bc96c9191
commit
cf38caeab1
@ -648,6 +648,10 @@ class ParserBase {
|
||||
return pending_error_handler()->stack_overflow();
|
||||
}
|
||||
void set_stack_overflow() { pending_error_handler()->set_stack_overflow(); }
|
||||
void CheckStackOverflow() {
|
||||
// Any further calls to Next or peek will return the illegal token.
|
||||
if (GetCurrentStackPosition() < stack_limit_) set_stack_overflow();
|
||||
}
|
||||
int script_id() { return script_id_; }
|
||||
void set_script_id(int id) { script_id_ = id; }
|
||||
|
||||
@ -669,32 +673,18 @@ class ParserBase {
|
||||
|
||||
V8_INLINE Token::Value Next() {
|
||||
if (stack_overflow()) return Token::ILLEGAL;
|
||||
{
|
||||
if (GetCurrentStackPosition() < stack_limit_) {
|
||||
// Any further calls to Next or peek will return the illegal token.
|
||||
// The current call must return the next token, which might already
|
||||
// have been peek'ed.
|
||||
set_stack_overflow();
|
||||
}
|
||||
}
|
||||
return scanner()->Next();
|
||||
}
|
||||
|
||||
void Consume(Token::Value token) {
|
||||
V8_INLINE void Consume(Token::Value token) {
|
||||
Token::Value next = scanner()->Next();
|
||||
if (GetCurrentStackPosition() < stack_limit_) {
|
||||
// Any further calls to Next or peek will return the illegal token.
|
||||
// The current call must return the next token, which might already
|
||||
// have been peek'ed.
|
||||
set_stack_overflow();
|
||||
}
|
||||
USE(next);
|
||||
USE(token);
|
||||
DCHECK_EQ(next, token);
|
||||
}
|
||||
|
||||
bool Check(Token::Value token) {
|
||||
Token::Value next = peek();
|
||||
V8_INLINE bool Check(Token::Value token) {
|
||||
Token::Value next = scanner()->peek();
|
||||
if (next == token) {
|
||||
Consume(next);
|
||||
return true;
|
||||
@ -1750,6 +1740,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBindingPattern(
|
||||
template <typename Impl>
|
||||
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
|
||||
bool* ok) {
|
||||
CheckStackOverflow();
|
||||
|
||||
// PrimaryExpression ::
|
||||
// 'this'
|
||||
// 'null'
|
||||
@ -2892,6 +2884,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
|
||||
classifier()->RecordFormalParameterInitializerError(
|
||||
scanner()->peek_location(), MessageTemplate::kYieldInParameter);
|
||||
Consume(Token::YIELD);
|
||||
|
||||
CheckStackOverflow();
|
||||
|
||||
// The following initialization is necessary.
|
||||
ExpressionT expression = impl()->NullExpression();
|
||||
bool delegating = false; // yield*
|
||||
@ -3074,6 +3069,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryOpExpression(
|
||||
function_state_->set_next_function_is_likely_called();
|
||||
}
|
||||
|
||||
CheckStackOverflow();
|
||||
|
||||
ExpressionT expression = ParseUnaryExpression(CHECK_OK);
|
||||
|
||||
if (op == Token::DELETE) {
|
||||
@ -3108,6 +3105,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrefixExpression(
|
||||
ArrowFormalParametersUnexpectedToken();
|
||||
Token::Value op = Next();
|
||||
int beg_pos = peek_position();
|
||||
|
||||
CheckStackOverflow();
|
||||
|
||||
ExpressionT expression = ParseUnaryExpression(CHECK_OK);
|
||||
expression = CheckAndRewriteReferenceExpression(
|
||||
expression, beg_pos, end_position(),
|
||||
@ -3127,6 +3127,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseAwaitExpression(
|
||||
int await_pos = peek_position();
|
||||
Consume(Token::AWAIT);
|
||||
|
||||
CheckStackOverflow();
|
||||
|
||||
ExpressionT value = ParseUnaryExpression(CHECK_OK);
|
||||
|
||||
classifier()->RecordBindingPatternError(
|
||||
@ -3341,6 +3343,9 @@ ParserBase<Impl>::ParseMemberWithPresentNewPrefixesExpression(bool* ok) {
|
||||
Consume(Token::NEW);
|
||||
int new_pos = position();
|
||||
ExpressionT result;
|
||||
|
||||
CheckStackOverflow();
|
||||
|
||||
if (peek() == Token::SUPER) {
|
||||
const bool is_new = true;
|
||||
result = ParseSuperExpression(is_new, CHECK_OK);
|
||||
@ -3400,10 +3405,6 @@ ParserBase<Impl>::ParseFunctionExpression(bool* ok) {
|
||||
if (impl()->ParsingDynamicFunctionDeclaration()) {
|
||||
// We don't want dynamic functions to actually declare their name
|
||||
// "anonymous". We just want that name in the toString().
|
||||
if (stack_overflow()) {
|
||||
*ok = false;
|
||||
return impl()->NullExpression();
|
||||
}
|
||||
Consume(Token::IDENTIFIER);
|
||||
DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS));
|
||||
} else if (peek_any_identifier()) {
|
||||
@ -3827,6 +3828,7 @@ template <typename Impl>
|
||||
typename ParserBase<Impl>::StatementT
|
||||
ParserBase<Impl>::ParseFunctionDeclaration(bool* ok) {
|
||||
Consume(Token::FUNCTION);
|
||||
|
||||
int pos = position();
|
||||
ParseFunctionFlags flags = ParseFunctionFlag::kIsNormal;
|
||||
if (Check(Token::MUL)) {
|
||||
@ -3844,6 +3846,7 @@ typename ParserBase<Impl>::StatementT
|
||||
ParserBase<Impl>::ParseHoistableDeclaration(
|
||||
ZonePtrList<const AstRawString>* names, bool default_export, bool* ok) {
|
||||
Consume(Token::FUNCTION);
|
||||
|
||||
int pos = position();
|
||||
ParseFunctionFlags flags = ParseFunctionFlag::kIsNormal;
|
||||
if (Check(Token::MUL)) {
|
||||
@ -3857,6 +3860,8 @@ typename ParserBase<Impl>::StatementT
|
||||
ParserBase<Impl>::ParseHoistableDeclaration(
|
||||
int pos, ParseFunctionFlags flags, ZonePtrList<const AstRawString>* names,
|
||||
bool default_export, bool* ok) {
|
||||
CheckStackOverflow();
|
||||
|
||||
// FunctionDeclaration ::
|
||||
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
||||
// 'function' '(' FormalParameters ')' '{' FunctionBody '}'
|
||||
@ -4456,10 +4461,6 @@ ParserBase<Impl>::ParseAsyncFunctionLiteral(bool* ok) {
|
||||
if (impl()->ParsingDynamicFunctionDeclaration()) {
|
||||
// We don't want dynamic functions to actually declare their name
|
||||
// "anonymous". We just want that name in the toString().
|
||||
if (stack_overflow()) {
|
||||
*ok = false;
|
||||
return impl()->NullExpression();
|
||||
}
|
||||
Consume(Token::IDENTIFIER);
|
||||
DCHECK(scanner()->CurrentMatchesContextual(Token::ANONYMOUS));
|
||||
} else if (peek_any_identifier()) {
|
||||
@ -4908,6 +4909,9 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
|
||||
|
||||
// Parse the statements and collect escaping labels.
|
||||
Expect(Token::LBRACE, CHECK_OK_CUSTOM(NullStatement));
|
||||
|
||||
CheckStackOverflow();
|
||||
|
||||
{
|
||||
BlockState block_state(zone(), &scope_);
|
||||
scope()->set_start_position(scanner()->location().beg_pos);
|
||||
@ -5247,7 +5251,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
|
||||
ZonePtrList<const AstRawString>* own_labels, bool* ok) {
|
||||
// DoStatement ::
|
||||
// 'do' Statement 'while' '(' Expression ')' ';'
|
||||
|
||||
auto loop =
|
||||
factory()->NewDoWhileStatement(labels, own_labels, peek_position());
|
||||
typename Types::Target target(this, loop);
|
||||
@ -5256,6 +5259,8 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDoWhileStatement(
|
||||
StatementT body = impl()->NullStatement();
|
||||
|
||||
Consume(Token::DO);
|
||||
|
||||
CheckStackOverflow();
|
||||
{
|
||||
SourceRangeScope range_scope(scanner(), &body_range);
|
||||
body = ParseStatement(nullptr, nullptr, CHECK_OK);
|
||||
|
Loading…
Reference in New Issue
Block a user