diff --git a/src/prism.c b/src/prism.c index 3afabc99d7..dbc08e4488 100644 --- a/src/prism.c +++ b/src/prism.c @@ -14568,10 +14568,15 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for * end * * - * It can recurse infinitely down, and splats are allowed to group arguments. + * The parentheses can be nested, and splats are allowed to group arguments. */ -static pm_multi_target_node_t * -parse_required_destructured_parameter(pm_parser_t *parser) { +static pm_node_t * +parse_required_destructured_parameter(pm_parser_t *parser, uint16_t depth) { + if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) { + pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP); + return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current))); + } + expect1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER); pm_multi_target_node_t *node = pm_multi_target_node_create(parser); @@ -14592,7 +14597,7 @@ parse_required_destructured_parameter(pm_parser_t *parser) { } if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) { - param = UP(parse_required_destructured_parameter(parser)); + param = parse_required_destructured_parameter(parser, (uint16_t) (depth + 1)); } else if (accept1(parser, PM_TOKEN_USTAR)) { pm_token_t star = parser->previous; pm_node_t *value = NULL; @@ -14625,7 +14630,7 @@ parse_required_destructured_parameter(pm_parser_t *parser) { expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER); pm_multi_target_node_closing_set(parser, node, &parser->previous); - return node; + return UP(node); } /** @@ -14762,7 +14767,7 @@ parse_parameters( switch (parser->current.type) { case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: { update_parameter_state(parser, &parser->current, &order); - pm_node_t *param = UP(parse_required_destructured_parameter(parser)); + pm_node_t *param = parse_required_destructured_parameter(parser, (uint16_t) (depth + 1)); if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) { pm_parameters_node_requireds_append(parser->arena, params, param); diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb index 0637671ba4..b9df0230d8 100644 --- a/test/prism/errors_test.rb +++ b/test/prism/errors_test.rb @@ -125,6 +125,14 @@ def test_unclosed_heredoc_and_interpolation assert_nil(statement.parts[0].statements) end + def test_nested_destructured_parameters + nested = "#{"(" * 10_000}a#{")" * 10_000}" + + ["def foo(#{nested}); end", "foo { |#{nested}| }", "->(#{nested}) {}"].each do |source| + assert_includes Prism.parse(source).errors.map(&:type), :nesting_too_deep + end + end + private def assert_errors(filepath, version)