Skip to content

Commit c041206

Browse files
committed
Add checks for break from proc-closure; fix #3640
1 parent ab85d3c commit c041206

2 files changed

Lines changed: 40 additions & 3 deletions

File tree

include/mruby/proc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ struct RProc {
5555
#define MRB_PROC_CFUNC_P(p) (((p)->flags & MRB_PROC_CFUNC) != 0)
5656
#define MRB_PROC_STRICT 256
5757
#define MRB_PROC_STRICT_P(p) (((p)->flags & MRB_PROC_STRICT) != 0)
58+
#define MRB_PROC_ORPHAN 512
59+
#define MRB_PROC_ORPHAN_P(p) (((p)->flags & MRB_PROC_ORPHAN) != 0)
5860

5961
#define mrb_proc_ptr(v) ((struct RProc*)(mrb_ptr(v)))
6062

src/vm.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,18 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
13281328
mrb_gc_arena_restore(mrb, ai);
13291329
if (mrb->exc) goto L_RAISE;
13301330
ci = mrb->c->ci;
1331+
if (GET_OPCODE(i) == OP_SENDB) {
1332+
mrb_value blk;
1333+
1334+
blk = ci->stackent[bidx];
1335+
if (mrb_type(blk) == MRB_TT_PROC) {
1336+
struct RProc *p = mrb_proc_ptr(blk);
1337+
1338+
if (p && p->env == ci[-1].env) {
1339+
p->flags |= MRB_PROC_ORPHAN;
1340+
}
1341+
}
1342+
}
13311343
if (!ci->target_class) { /* return from context modifying method (resume/yield) */
13321344
if (ci->acc == CI_ACC_RESUMED) {
13331345
mrb->jmp = prev_jmp;
@@ -1748,8 +1760,29 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
17481760
/* fall through */
17491761
CASE(OP_RETURN) {
17501762
/* A B return R(A) (B=normal,in-block return/break) */
1763+
mrb_callinfo *ci;
1764+
1765+
ci = mrb->c->ci;
1766+
if (ci->mid) {
1767+
mrb_value blk;
1768+
1769+
if (ci->argc < 0) {
1770+
blk = regs[2];
1771+
}
1772+
else {
1773+
blk = regs[ci->argc+1];
1774+
}
1775+
if (mrb_type(blk) == MRB_TT_PROC) {
1776+
struct RProc *p = mrb_proc_ptr(blk);
1777+
1778+
if (ci > mrb->c->cibase && p->env == ci[-1].env) {
1779+
p->flags |= MRB_PROC_ORPHAN;
1780+
}
1781+
}
1782+
}
1783+
17511784
if (mrb->exc) {
1752-
mrb_callinfo *ci, *ci0;
1785+
mrb_callinfo *ci0;
17531786
mrb_value *stk;
17541787

17551788
L_RAISE:
@@ -1805,7 +1838,6 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
18051838
pc = mrb->c->rescue[--mrb->c->ridx];
18061839
}
18071840
else {
1808-
mrb_callinfo *ci = mrb->c->ci;
18091841
int acc;
18101842
mrb_value v = regs[GETARG_A(i)];
18111843

@@ -1864,7 +1896,7 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
18641896
break;
18651897
case OP_R_BREAK:
18661898
if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN;
1867-
if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
1899+
if (MRB_PROC_ORPHAN_P(proc)) {
18681900
mrb_value exc;
18691901

18701902
L_BREAK_ERROR:
@@ -1873,6 +1905,9 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
18731905
mrb_exc_set(mrb, exc);
18741906
goto L_RAISE;
18751907
}
1908+
if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
1909+
goto L_BREAK_ERROR;
1910+
}
18761911
/* break from fiber block */
18771912
if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) {
18781913
struct mrb_context *c = mrb->c;

0 commit comments

Comments
 (0)