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