From 9f0950da13596edcf64b821f696426445d323d01 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 29 Dec 2025 22:28:45 +0900 Subject: [PATCH] codegen.c: fix stack tracking in pattern match branching code When generating code for pattern matching with potential failures, the success and failure paths both need to pop the matched value. At runtime, only one path executes. But during codegen, both pop() calls affected the compile-time stack pointer (cursp), corrupting register allocation and causing heap-buffer-overflow when accessing symbol tables with wrong indices. Fix by saving/restoring the stack pointer around the branch point, so each path correctly tracks the stack state independently. Co-authored-by: Claude --- mrbgems/mruby-compiler/core/codegen.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 32b850f84..8ff2cdb65 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -6603,13 +6603,14 @@ codegen(codegen_scope *s, node *tree, int val) /* Generate pattern matching code */ codegen_pattern(s, mp->pattern, head, &fail_pos, known_array_len); - /* Pattern matched */ - pop(); /* pop the value */ pattern_fail_handling: if (fail_pos != JMPLINK_START) { /* Pattern can fail - generate failure handling code */ uint32_t match_pos; + int saved_sp = cursp(); /* save stack pointer before branching */ + /* Success path: pattern matched */ + pop(); /* pop the value */ if (val) { /* 'in' pattern returns true, '=>' pattern returns nil */ if (mp->raise_on_fail) { @@ -6636,7 +6637,8 @@ codegen(codegen_scope *s, node *tree, int val) dispatch_linked(s, fail_pos); } - /* Pattern failed */ + /* Failure path: restore stack pointer (value still on stack at runtime) */ + s->sp = saved_sp; pop(); /* pop the value */ if (mp->raise_on_fail) { /* expr => pattern: raise NoMatchingPatternError */ @@ -6667,7 +6669,8 @@ codegen(codegen_scope *s, node *tree, int val) dispatch(s, match_pos); } else { - /* Pattern always matches - push result if needed */ + /* Pattern always matches - pop value and push result if needed */ + pop(); /* pop the value */ if (val) { if (mp->raise_on_fail) { gen_load_nil(s, 1); /* '=>' pattern returns nil */