From 4380773666b058128b32bc1de700e94e6434bd3d Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 8 Mar 2024 21:50:46 +0900 Subject: [PATCH] Fix `OP_STOP` with exception Previously, `mrb->exc` would remain replaced by a `break` object if a rewind operation was performed during the processing of a `OP_STOP` instruction. This problem has existed since #5060, when it was introduced in mruby-3.0. However, as of mruby-3.0, a manual or third-party generator is required to cause the `OP_STOP` instruction to be issued. Therefore, it is believed that this has not had an impact until now. --- src/vm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vm.c b/src/vm.c index ae10ed707..fc5b6f9e0 100644 --- a/src/vm.c +++ b/src/vm.c @@ -3068,18 +3068,22 @@ RETRY_TRY_BLOCK: CASE(OP_STOP, Z) { /* stop VM */ + mrb_value v; + v = mrb->exc ? mrb_obj_value(mrb->exc) : mrb_nil_value(); CHECKPOINT_RESTORE(RBREAK_TAG_STOP) { - /* do nothing */ + struct RBreak *brk = (struct RBreak*)mrb->exc; + v = mrb_break_value_get(brk); } CHECKPOINT_MAIN(RBREAK_TAG_STOP) { - UNWIND_ENSURE(mrb, mrb->c->ci, mrb->c->ci->pc, RBREAK_TAG_STOP, mrb->c->ci, mrb_nil_value()); + UNWIND_ENSURE(mrb, mrb->c->ci, mrb->c->ci->pc, RBREAK_TAG_STOP, mrb->c->ci, v); } CHECKPOINT_END(RBREAK_TAG_STOP); mrb->jmp = prev_jmp; - if (mrb->exc) { - mrb_assert(mrb->exc->tt == MRB_TT_EXCEPTION); - return mrb_obj_value(mrb->exc); + if (!mrb_nil_p(v)) { + mrb->exc = mrb_obj_ptr(v); + return v; } + mrb->exc = NULL; return regs[irep->nlocals]; } }