diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-10-28 21:09:25 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-10-28 23:08:31 +0900 |
| commit | c7c9543bed57db12fd8aa57391e0b652ee27cb23 (patch) | |
| tree | 0d86333105b620e7ed735a58708f193c03f6befd /mrbgems/mruby-eval | |
| parent | 57dad6e3fd1a670702bd252be07d2999b6b5735d (diff) | |
| download | mruby-c7c9543bed57db12fd8aa57391e0b652ee27cb23.tar.gz mruby-c7c9543bed57db12fd8aa57391e0b652ee27cb23.zip | |
Fixed UPVAR gotchas; fix #3835
Both `uvenv` function and `env` generation in `create_proc_from_string`
function have bugs to handling enclosed environment objects.
Diffstat (limited to 'mrbgems/mruby-eval')
| -rw-r--r-- | mrbgems/mruby-eval/src/eval.c | 58 |
1 files changed, 30 insertions, 28 deletions
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 7061565ea..997b69e25 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -12,21 +12,13 @@ mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self); static struct mrb_irep * get_closure_irep(mrb_state *mrb, int level) { - struct mrb_context *c = mrb->c; - struct RProc *proc = c->ci[-1].proc; + struct RProc *proc = mrb->c->ci[-1].proc; - if (level == 0) { - if (MRB_PROC_CFUNC_P(proc)) { - return NULL; - } - return proc->body.irep; - } - - while (--level) { - proc = proc->upper; + while (level--) { if (!proc) return NULL; + proc = proc->upper; } - + if (!proc) return NULL; if (MRB_PROC_CFUNC_P(proc)) { return NULL; } @@ -60,7 +52,7 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest) int pos; for (level = 0; (virep = get_closure_irep(mrb, level)); level++) { - if (!virep || virep->lv == NULL) { + if (virep->lv == NULL) { continue; } for (pos = 0; pos < virep->nlocals - 1; pos++) { @@ -123,7 +115,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top) if (GETARG_C(c) != 0) { break; } - { + else { mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest); if (arg != 0) { /* must replace */ @@ -197,7 +189,7 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, struct mrb_parser_state *p; struct RProc *proc; struct REnv *e; - mrb_callinfo *ci = mrb->c->ci; + mrb_callinfo *ci = &mrb->c->ci[-1]; /* callinfo of eval caller */ struct RClass *target_class = NULL; int bidx; @@ -246,19 +238,29 @@ create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, mrbc_context_free(mrb, cxt); mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error"); } - target_class = MRB_PROC_TARGET_CLASS(ci[-1].proc); - e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, - (struct RClass*)target_class); - e->mid = ci->mid; - e->stack = ci->stackent; - MRB_ENV_SET_STACK_LEN(e, ci->proc->body.irep->nlocals); - bidx = ci->argc; - if (ci->argc < 0) bidx = 2; - else bidx += 1; - MRB_ENV_SET_BIDX(e, bidx); - proc->e.env = e; - proc->flags |= MRB_PROC_ENVSET; - ci->target_class = target_class; + target_class = MRB_PROC_TARGET_CLASS(ci->proc); + if (!MRB_PROC_CFUNC_P(ci->proc)) { + if (ci->env) { + e = ci->env; + } + else { + e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, + (struct RClass*)target_class); + e->mid = ci->mid; + e->stack = ci[1].stackent; + e->cxt = mrb->c; + MRB_ENV_SET_STACK_LEN(e, ci->proc->body.irep->nlocals); + bidx = ci->argc; + if (ci->argc < 0) bidx = 2; + else bidx += 1; + MRB_ENV_SET_BIDX(e, bidx); + } + proc->e.env = e; + proc->flags |= MRB_PROC_ENVSET; + mrb_field_write_barrier(mrb, (struct RBasic*)proc, (struct RBasic*)e); + } + proc->upper = ci->proc; + mrb->c->ci->target_class = target_class; patch_irep(mrb, proc->body.irep, 0, proc->body.irep); /* mrb_codedump_all(mrb, proc); */ |
