From 2ba1d383a54049c36c41b3bba8c43ed8d0e1926c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 3 Jul 2026 16:12:09 +0900 Subject: [PATCH] Fix stack-use-after-return with unterminated heredocs The heredoc handler in parse_expression_prefix stores the address of its stack-local common_whitespace into the heredoc lex mode. When the heredoc terminator is missing, expect1_heredoc_term reports an error without popping the lex mode, so the stored pointer outlives the stack frame and subsequent lexing reads dead stack memory. Clear the pointer before leaving the handler; the lexer already guards against NULL. Co-authored-by: Claude --- src/prism.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/prism.c b/src/prism.c index 311291aff5..511223aaee 100644 --- a/src/prism.c +++ b/src/prism.c @@ -19816,6 +19816,18 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, u } } + /* If a missing terminator left this heredoc's lex mode on the + * stack, it still points at our stack-local common_whitespace. + * Clear the pointer so that subsequent lexing cannot read from + * this function's dead stack frame. */ + pm_lex_mode_t *whitespace_mode = parser->lex_modes.current; + do { + if (whitespace_mode->mode == PM_LEX_HEREDOC && whitespace_mode->as.heredoc.common_whitespace == &common_whitespace) { + whitespace_mode->as.heredoc.common_whitespace = NULL; + } + whitespace_mode = whitespace_mode->prev; + } while (whitespace_mode != NULL); + if (match1(parser, PM_TOKEN_STRING_BEGIN)) { return parse_strings(parser, node, false, (uint16_t) (depth + 1)); }