For information.
There is a problem in the scenario where OP_STOP is issued with an exception object, or where a break object is entered into mrb->exc by unwind while processing OP_STOP.
However, since OP_STOP is never used when it is generated, I don't think there is a problem.
The patch is already written and will be sent as another PR if this PR is accepted or rejected.
diff --git a/src/vm.c b/src/vm.c index 4e8283e18..9f80fce46 100644 --- a/src/vm.c +++ b/src/vm.c @@ -3078,18 +3078,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]; } }