Use `proc->env` to check `block_given?` if possible; fix #5039

This bug has been there since mruby 1.4.0 (2018-04).
parent e41f1f51
...@@ -99,6 +99,18 @@ mrb_obj_id_m(mrb_state *mrb, mrb_value self) ...@@ -99,6 +99,18 @@ mrb_obj_id_m(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(mrb_obj_id(self)); return mrb_fixnum_value(mrb_obj_id(self));
} }
static int
env_bidx(struct REnv *e)
{
int bidx;
/* use saved block arg position */
bidx = MRB_ENV_BIDX(e);
/* bidx may be useless (e.g. define_method) */
if (bidx >= MRB_ENV_LEN(e)) return -1;
return bidx;
}
/* 15.3.1.2.2 */ /* 15.3.1.2.2 */
/* 15.3.1.2.5 */ /* 15.3.1.2.5 */
/* 15.3.1.3.6 */ /* 15.3.1.3.6 */
...@@ -129,6 +141,8 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) ...@@ -129,6 +141,8 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
mrb_callinfo *ci = &mrb->c->ci[-1]; mrb_callinfo *ci = &mrb->c->ci[-1];
mrb_callinfo *cibase = mrb->c->cibase; mrb_callinfo *cibase = mrb->c->cibase;
mrb_value *bp; mrb_value *bp;
int bidx;
struct REnv *e = NULL;
struct RProc *p; struct RProc *p;
if (ci <= cibase) { if (ci <= cibase) {
...@@ -139,29 +153,36 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) ...@@ -139,29 +153,36 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
/* search method/class/module proc */ /* search method/class/module proc */
while (p) { while (p) {
if (MRB_PROC_SCOPE_P(p)) break; if (MRB_PROC_SCOPE_P(p)) break;
e = MRB_PROC_ENV(p);
p = p->upper; p = p->upper;
} }
if (p == NULL) return mrb_false_value(); if (p == NULL) return mrb_false_value();
if (e) {
bidx = env_bidx(e);
if (bidx < 0) return mrb_false_value();
bp = &e->stack[bidx];
goto block_given;
}
/* search ci corresponding to proc */ /* search ci corresponding to proc */
while (cibase < ci) { while (cibase < ci) {
if (ci->proc == p) break; if (ci->proc == p) break;
ci--; ci--;
} }
if (ci == cibase) { if (ci == cibase) {
return mrb_false_value(); /* proc is closure */
if (!MRB_PROC_ENV_P(p)) return mrb_false_value();
e = MRB_PROC_ENV(p);
bidx = env_bidx(e);
if (bidx < 0) return mrb_false_value();
bp = &e->stack[bidx];
} }
else if (ci->env) { else if (ci->env) {
struct REnv *e = ci->env; e = ci->env;
int bidx;
/* top-level does not have block slot (always false) */ /* top-level does not have block slot (always false) */
if (e->stack == mrb->c->stbase) if (e->stack == mrb->c->stbase) return mrb_false_value();
return mrb_false_value(); bidx = env_bidx(e);
/* use saved block arg position */
bidx = MRB_ENV_BIDX(e);
/* bidx may be useless (e.g. define_method) */ /* bidx may be useless (e.g. define_method) */
if (bidx >= MRB_ENV_LEN(e)) if (bidx < 0) return mrb_false_value();
return mrb_false_value();
bp = &e->stack[bidx]; bp = &e->stack[bidx];
} }
else { else {
...@@ -173,6 +194,7 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) ...@@ -173,6 +194,7 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self)
bp++; bp++;
} }
} }
block_given:
if (mrb_nil_p(*bp)) if (mrb_nil_p(*bp))
return mrb_false_value(); return mrb_false_value();
return mrb_true_value(); return mrb_true_value();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment