From 4c196dcdaaf4127e2ce988fb79f1912c78b9dca8 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 3 Apr 2021 21:20:59 +0900 Subject: Reorganize `mcall()` in `mruby-method`. Use `mrb_exec_irep()`. If possible, re-entry into the VM will be suppressed. Note that due to the effect of being a tail-call, the backtrace of `Method#call` will be lost, and it will look as if the target method was called directly. This change fixes the problem of infinite loops when redefining methods that make block calls using `mruby-method`. ```console % bin/mruby -e 'mm = method(:proc); define_method(:proc, ->(*a, &b) { mm.call(*a, &b) }); p proc { 1 }' trace (most recent call last): [257] -e:1 [256] -e:1:in proc [255] -e:1:in proc ...SNIP... [1] -e:1:in proc -e:1:in proc: stack level too deep (SystemStackError) ``` --- src/vm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index d7f2f58d7..dbc8bd88a 100644 --- a/src/vm.c +++ b/src/vm.c @@ -585,7 +585,9 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t postho else { mrb_value ret; if (MRB_PROC_CFUNC_P(p)) { + cipush(mrb, 0, CI_ACC_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->argc); ret = MRB_PROC_CFUNC(p)(mrb, self); + cipop(mrb); } else { int keep = (ci->argc < 0 ? 1 : ci->argc) + 2 /* receiver + block */; -- cgit v1.2.3