mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Make mrb_env_unshare() call in mrb_vm_run()
Move the detachment of the "env" object, now done by `mrb_top_run()` by #5904, to `mrb_vm_run()`. This is because `mrb_vm_run()` can remove `mrb_env_unshare()` which is called from `bin/mirb`. Also, even if the mruby VM is already running, either of the following conditions should be used to detach "env": - If the `stack_keep` variable is 0. - If the stack length of "env" is longer than `irep->nlocals`. The reason for the change is that the stack beyond `irep->nlocals` is used inside the called method, and previously it was possible to reference and manipulate the state inside the method via "env". env stack | | main stack | top | m1 | m2 | |<--------------->| operable via env stack (including self) If the problematic block is called from the `m2` method above, it is possible to replace `self` in `m1` and `m2` as well as the internal variables. This change may cause compatibility problems, but I believe it is better to make `MRB_API`, `mrb_vm_run()` safe. If a dangerous procedure is absolutely necessary, `mrb_vm_exec()` can still be called as before.
This commit is contained in:
@@ -1269,6 +1269,13 @@ mrb_vm_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int sta
|
||||
}
|
||||
if (stack_keep > nregs)
|
||||
nregs = stack_keep;
|
||||
else {
|
||||
struct REnv *e = CI_ENV(mrb->c->ci);
|
||||
if (stack_keep == 0 || (e && irep->nlocals < MRB_ENV_LEN(e))) {
|
||||
mrb_vm_ci_env_set(mrb->c->ci, NULL);
|
||||
mrb_env_unshare(mrb, e, FALSE);
|
||||
}
|
||||
}
|
||||
mrb_stack_extend(mrb, nregs);
|
||||
stack_clear(c->ci->stack + stack_keep, nregs - stack_keep);
|
||||
c->ci->stack[0] = self;
|
||||
@@ -3096,11 +3103,6 @@ mrb_top_run(mrb_state *mrb, const struct RProc *proc, mrb_value self, mrb_int st
|
||||
return mrb_vm_run(mrb, proc, self, stack_keep);
|
||||
}
|
||||
if (mrb->c->ci == mrb->c->cibase) {
|
||||
if (stack_keep == 0) {
|
||||
struct REnv *e = mrb_vm_ci_env(mrb->c->ci);
|
||||
mrb_vm_ci_env_set(mrb->c->ci, NULL);
|
||||
mrb_env_unshare(mrb, e, FALSE);
|
||||
}
|
||||
return mrb_vm_run(mrb, proc, self, stack_keep);
|
||||
}
|
||||
cipush(mrb, 0, CINFO_SKIP, mrb->object_class, NULL, NULL, 0, 0);
|
||||
|
||||
Reference in New Issue
Block a user