Detect cyclic link of class path references; fix #3926

parent 3ae621fc
...@@ -955,27 +955,61 @@ find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c) ...@@ -955,27 +955,61 @@ find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c)
return arg.sym; return arg.sym;
} }
static struct RClass*
outer_class(mrb_state *mrb, struct RClass *c)
{
mrb_value ov;
ov = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"));
if (mrb_nil_p(ov)) return NULL;
switch (mrb_type(ov)) {
case MRB_TT_CLASS:
case MRB_TT_MODULE:
return mrb_class_ptr(ov);
default:
break;
}
return NULL;
}
static mrb_bool
detect_outer_loop(mrb_state *mrb, struct RClass *c)
{
struct RClass *t = c; /* tortoise */
struct RClass *h = c; /* hare */
for (;;) {
if (h == NULL) return FALSE;
h = outer_class(mrb, h);
if (h == NULL) return FALSE;
h = outer_class(mrb, h);
t = outer_class(mrb, t);
if (t == h) return TRUE;
}
}
mrb_value mrb_value
mrb_class_find_path(mrb_state *mrb, struct RClass *c) mrb_class_find_path(mrb_state *mrb, struct RClass *c)
{ {
mrb_value outer, path; struct RClass *outer;
mrb_value path;
mrb_sym name; mrb_sym name;
const char *str; const char *str;
mrb_int len; mrb_int len;
mrb_sym osym = mrb_intern_lit(mrb, "__outer__");
outer = mrb_obj_iv_get(mrb, (struct RObject*)c, osym); if (detect_outer_loop(mrb, c)) return mrb_nil_value();
if (mrb_nil_p(outer)) return outer; outer = outer_class(mrb, c);
name = find_class_sym(mrb, mrb_class_ptr(outer), c); if (outer == NULL) return mrb_nil_value();
name = find_class_sym(mrb, outer, c);
if (name == 0) return mrb_nil_value(); if (name == 0) return mrb_nil_value();
str = mrb_class_name(mrb, mrb_class_ptr(outer)); str = mrb_class_name(mrb, outer);
path = mrb_str_new_capa(mrb, 40); path = mrb_str_new_capa(mrb, 40);
mrb_str_cat_cstr(mrb, path, str); mrb_str_cat_cstr(mrb, path, str);
mrb_str_cat_cstr(mrb, path, "::"); mrb_str_cat_cstr(mrb, path, "::");
str = mrb_sym2name_len(mrb, name, &len); str = mrb_sym2name_len(mrb, name, &len);
mrb_str_cat(mrb, path, str, len); mrb_str_cat(mrb, path, str, len);
iv_del(mrb, c->iv, osym, NULL); iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL);
iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path); iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path);
mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path);
return path; return path;
......
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