[wgsl-parser] Set max recursion depth on const_expr The `const_expr` can recurse into itself if there are type declarations inside the const_expr (e.g. vec2<f32>(f32(1.0), f32(2.0))). Currently there is no limit on the amount of recursion which can be triggered. This CL sets a limit of 128 nested type declarations at which point an error will be emitted. Bug: chromium:1112144 Change-Id: Ifae45034dc9de35aed78ba8eddf584a46c7a55ce Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/27340 Reviewed-by: dan sinclair <dsinclair@chromium.org> Reviewed-by: Ryan Harrison <rharrison@chromium.org> Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index dcd2b44..7495b5a 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc
@@ -67,6 +67,11 @@ namespace wgsl { namespace { +/// Controls the maximum number of times we'll call into the const_expr function +/// from itself. This is to guard against stack overflow when there is an +/// excessive number of type constructors inside the const_expr. +uint32_t kMaxConstExprDepth = 128; + ast::Builtin ident_to_builtin(const std::string& str) { if (str == "position") { return ast::Builtin::kPosition; @@ -2960,7 +2965,18 @@ // : type_decl PAREN_LEFT (const_expr COMMA)? const_expr PAREN_RIGHT // | const_literal std::unique_ptr<ast::ConstructorExpression> ParserImpl::const_expr() { + return const_expr_internal(0); +} + +std::unique_ptr<ast::ConstructorExpression> ParserImpl::const_expr_internal( + uint32_t depth) { auto t = peek(); + + if (depth > kMaxConstExprDepth) { + set_error(t, "max const_expr depth reached"); + return nullptr; + } + auto source = t.source(); auto* type = type_decl(); @@ -2972,7 +2988,7 @@ } ast::ExpressionList params; - auto param = const_expr(); + auto param = const_expr_internal(depth + 1); if (has_error()) return nullptr; if (param == nullptr) { @@ -2987,7 +3003,7 @@ next(); // Consume the peek - param = const_expr(); + param = const_expr_internal(depth + 1); if (has_error()) return nullptr; if (param == nullptr) {
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h index 28c5e33..360ad76 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h
@@ -362,6 +362,9 @@ uint32_t array_decoration_list(); ast::type::Type* type_decl_matrix(Token t); + std::unique_ptr<ast::ConstructorExpression> const_expr_internal( + uint32_t depth); + Context& ctx_; std::string error_; std::unique_ptr<Lexer> lexer_;
diff --git a/src/reader/wgsl/parser_impl_const_expr_test.cc b/src/reader/wgsl/parser_impl_const_expr_test.cc index 4f4ecbc..86392a3 100644 --- a/src/reader/wgsl/parser_impl_const_expr_test.cc +++ b/src/reader/wgsl/parser_impl_const_expr_test.cc
@@ -122,6 +122,22 @@ EXPECT_EQ(p->error(), "1:1: unknown type alias 'invalid'"); } +TEST_F(ParserImplTest, ConstExpr_Recursion) { + std::stringstream out; + for (size_t i = 0; i < 200; i++) { + out << "f32("; + } + out << "1.0"; + for (size_t i = 0; i < 200; i++) { + out << ")"; + } + auto* p = parser(out.str()); + auto e = p->const_expr(); + ASSERT_TRUE(p->has_error()); + ASSERT_EQ(e, nullptr); + EXPECT_EQ(p->error(), "1:517: max const_expr depth reached"); +} + } // namespace } // namespace wgsl } // namespace reader