reader/wgsl: Prevent stack overflow in unary_expression() Fixed: chromium:1209237 Change-Id: I14b4777aaee3ee7a34baf8a218db28f54b81af84 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/55253 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: James Price <jrprice@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index bb6c886..71ba2d0 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc
@@ -52,10 +52,10 @@ template <typename T> using Maybe = ParserImpl::Maybe<T>; -/// Controls the maximum number of times we'll call into the sync() function -/// from itself. This is to guard against stack overflow when there is an -/// excessive number of blocks. -constexpr uint32_t kMaxSyncDepth = 128; +/// Controls the maximum number of times we'll call into the sync() and +/// unary_expression() functions from themselves. This is to guard against stack +/// overflow when there is an excessive number of blocks. +constexpr uint32_t kMaxParseDepth = 128; /// The maximum number of tokens to look ahead to try and sync the /// parser on error. @@ -2327,7 +2327,18 @@ return singular_expression(); } + if (parse_depth_ >= kMaxParseDepth) { + // We've hit a maximum parser recursive depth. + // We can't call into unary_expression() as we might stack overflow. + // Instead, report an error + add_error(peek(), "maximum parser recursive depth reached"); + return Failure::kErrored; + } + + ++parse_depth_; auto expr = unary_expression(); + --parse_depth_; + if (expr.errored) { return Failure::kErrored; } @@ -3268,7 +3279,7 @@ template <typename F, typename T> T ParserImpl::sync(Token::Type tok, F&& body) { - if (sync_depth_ >= kMaxSyncDepth) { + if (parse_depth_ >= kMaxParseDepth) { // We've hit a maximum parser recursive depth. // We can't call into body() as we might stack overflow. // Instead, report an error... @@ -3282,9 +3293,9 @@ sync_tokens_.push_back(tok); - ++sync_depth_; + ++parse_depth_; auto result = body(); - --sync_depth_; + --parse_depth_; if (sync_tokens_.back() != tok) { TINT_ICE(builder_.Diagnostics()) << "sync_tokens is out of sync";
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h index 0fa2773..55cd25a 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h
@@ -871,7 +871,7 @@ std::deque<Token> token_queue_; Token last_token_; bool synchronized_ = true; - uint32_t sync_depth_ = 0; + uint32_t parse_depth_ = 0; std::vector<Token::Type> sync_tokens_; int silence_errors_ = 0; std::unordered_map<std::string, const ast::TypeDecl*> registered_types_;
diff --git a/src/reader/wgsl/parser_impl_const_expr_test.cc b/src/reader/wgsl/parser_impl_const_expr_test.cc index 5a43c48..db05cf9 100644 --- a/src/reader/wgsl/parser_impl_const_expr_test.cc +++ b/src/reader/wgsl/parser_impl_const_expr_test.cc
@@ -154,6 +154,20 @@ EXPECT_EQ(p->error(), "1:517: maximum parser recursive depth reached"); } +TEST_F(ParserImplTest, UnaryOp_Recursion) { + std::stringstream out; + for (size_t i = 0; i < 200; i++) { + out << "!"; + } + out << "1.0"; + auto p = parser(out.str()); + auto e = p->unary_expression(); + ASSERT_TRUE(p->has_error()); + ASSERT_TRUE(e.errored); + ASSERT_EQ(e.value, nullptr); + EXPECT_EQ(p->error(), "1:130: maximum parser recursive depth reached"); +} + } // namespace } // namespace wgsl } // namespace reader