From e50f15c1c6e131fa7934355eb02b8173b13df415 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 13 Jan 2026 14:46:33 +0900 Subject: [PATCH] mruby-compiler: fix bytecode corruption in pattern matching optimization The JMPNOT-to-JMPIF optimization assumed fail_pos always came from a 4-byte JMPNOT instruction. When a pinned variable is undefined, NODE_PAT_PIN generates a 3-byte OP_JMP instead, causing fail_pos - 2 to point into the previous instruction and corrupt its operand. Add a check to verify the instruction at fail_pos - 2 is actually OP_JMPNOT before modifying it. Fixes #6701 Co-authored-by: Claude --- mrbgems/mruby-compiler/core/codegen.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 1e45a0f25..179a9ac24 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -6626,10 +6626,12 @@ codegen(codegen_scope *s, node *tree, int val) } /* Optimize: single JMPNOT can be inverted to JMPIF, eliminating JMP */ - /* Conditions: (1) single entry in fail_pos chain, and - * (2) JMPNOT is immediately before current position (no code between) */ + /* Conditions: (1) single entry in fail_pos chain, + * (2) JMPNOT is immediately before current position (no code between), and + * (3) the instruction is actually JMPNOT (not JMP from undefined pinned var) */ if ((int32_t)(fail_pos + 2) + (int16_t)PEEK_S(s->iseq+fail_pos) == 0 && - fail_pos + 2 == s->pc) { + fail_pos + 2 == s->pc && + s->iseq[fail_pos - 2] == OP_JMPNOT) { /* Single failure point - invert JMPNOT to JMPIF */ s->iseq[fail_pos - 2] = OP_JMPIF; match_pos = fail_pos;