From 9bd2370978448b6b96ceb15bc785e1267bc4be45 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 d997c63d16..0e2d541bc4 100644 --- a/src/prism.c +++ b/src/prism.c @@ -19712,6 +19712,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)); }