mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-compiler: fix JMPNOT-to-MATCHERR rewriting in pattern match codegen
The MATCHERR optimization replaced JMPNOT (BS, 4 bytes) with MATCHERR (B, 2 bytes) and rewound s->pc by 2. When pattern alternation (e.g. a|B) dispatched a success jump to s->pc before the optimization, the rewind shifted subsequent instructions and the jump landed in the middle of the next instruction, causing out-of-bounds access at runtime. Replace JMPNOT in-place with MATCHERR+NOP+NOP to keep the same 4-byte size, so s->pc does not change and jump targets stay valid. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6701,11 +6701,12 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
fail_pos + 2 == s->pc &&
|
||||
s->iseq[fail_pos - 2] == OP_JMPNOT) {
|
||||
if (mp->raise_on_fail) {
|
||||
/* Single failure point with raise - replace JMPNOT with MATCHERR */
|
||||
int reg = s->iseq[fail_pos - 1]; /* Register from JMPNOT */
|
||||
s->pc = fail_pos - 2; /* Rewind past JMPNOT */
|
||||
s->lastpc = s->pc;
|
||||
genop_1(s, OP_MATCHERR, reg); /* Emit MATCHERR with the register */
|
||||
/* Replace JMPNOT(BS,4bytes) with MATCHERR(B,2bytes)+NOP+NOP;
|
||||
* keep the same size so that any jump targeting s->pc stays valid */
|
||||
s->iseq[fail_pos - 2] = OP_MATCHERR;
|
||||
/* fail_pos-1 already holds the register operand */
|
||||
s->iseq[fail_pos] = OP_NOP;
|
||||
s->iseq[fail_pos + 1] = OP_NOP;
|
||||
s->sp = saved_sp - 1;
|
||||
if (val) push();
|
||||
break; /* Pattern matching complete */
|
||||
|
||||
Reference in New Issue
Block a user