Fix infinite spin in wgsl parser

If the parser hits a `maximum parser recursive depth reached` situation, then we need to try and resynchronize the parser.

If we fail to do this, then the synchronized_ flag may remain true, and the parser will believe progress is still being made.
In this situation the parser may try to reparse the same token, forever.

By calling sync_to() we either find the end of the block, and forward progress can be made, or synchronized_ is set to false, and the parser can error out cleanly.

Add test case from fuzzer report.

Fixed: chromium:1180128
Change-Id: I893077677fd3dfbd4b9b400cd32db842b06db500
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/42029
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2021-02-19 20:01:43 +00:00 committed by Commit Bot service account
parent 527a0bbf25
commit 767df5f03b
4 changed files with 46 additions and 1 deletions

View File

@ -1036,6 +1036,7 @@ source_set("tint_unittests_wgsl_reader_src") {
"src/reader/wgsl/parser_impl_assignment_stmt_test.cc",
"src/reader/wgsl/parser_impl_body_stmt_test.cc",
"src/reader/wgsl/parser_impl_break_stmt_test.cc",
"src/reader/wgsl/parser_impl_bug_cases_test.cc",
"src/reader/wgsl/parser_impl_call_stmt_test.cc",
"src/reader/wgsl/parser_impl_case_body_test.cc",
"src/reader/wgsl/parser_impl_const_expr_test.cc",

View File

@ -567,6 +567,7 @@ if(${TINT_BUILD_TESTS})
reader/wgsl/parser_impl_assignment_stmt_test.cc
reader/wgsl/parser_impl_body_stmt_test.cc
reader/wgsl/parser_impl_break_stmt_test.cc
reader/wgsl/parser_impl_bug_cases_test.cc
reader/wgsl/parser_impl_call_stmt_test.cc
reader/wgsl/parser_impl_case_body_test.cc
reader/wgsl/parser_impl_const_expr_test.cc

View File

@ -3162,7 +3162,15 @@ T ParserImpl::expect_lt_gt_block(const std::string& use, F&& body) {
template <typename F, typename T>
T ParserImpl::sync(Token::Type tok, F&& body) {
if (sync_depth_ >= kMaxSyncDepth) {
return add_error(peek(), "maximum parser recursive depth reached");
// We've hit a maximum parser recursive depth.
// We can't call into body() as we might stack overflow.
// Instead, report an error...
add_error(peek(), "maximum parser recursive depth reached");
// ...and try to resynchronize. If we cannot resynchronize to `tok` then
// synchronized_ is set to false, and the parser knows that forward progress
// is not being made.
sync_to(tok, /* consume: */ true);
return Failure::kErrored;
}
sync_tokens_.push_back(tok);

View File

@ -0,0 +1,35 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "gtest/gtest.h"
#include "src/ast/break_statement.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
namespace {
TEST_F(ParserImplTest, Bug_chromium_1180130) {
auto p = parser(
R"(a;{}}a;}};{{{;{}};{};{}}a;{}};{{{}};{{{;{}};{};{}}a;{}};{{{}}{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{{{;u[([[,a;{}}a;{}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{z{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}}i;{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{;u[[a,([}};{{{;{}})");
EXPECT_FALSE(p->Parse());
EXPECT_TRUE(p->has_error());
}
} // namespace
} // namespace wgsl
} // namespace reader
} // namespace tint