diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2018-01-17 09:38:59 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2018-01-17 09:41:26 +0900 |
| commit | e5fb21b6d281e76ed1aadf488706600739b7f787 (patch) | |
| tree | e4f79676bfb3765d3dd6508302586dfd7ece7082 /src | |
| parent | 3ae621fcb32a87e65de0ad68c291a12d315a81dd (diff) | |
| download | mruby-e5fb21b6d281e76ed1aadf488706600739b7f787.tar.gz mruby-e5fb21b6d281e76ed1aadf488706600739b7f787.zip | |
Detect cyclic link of class path references; fix #3926
Diffstat (limited to 'src')
| -rw-r--r-- | src/variable.c | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/src/variable.c b/src/variable.c index 968fc2fc1..de36efac6 100644 --- a/src/variable.c +++ b/src/variable.c @@ -955,27 +955,61 @@ find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c) 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_class_find_path(mrb_state *mrb, struct RClass *c) { - mrb_value outer, path; + struct RClass *outer; + mrb_value path; mrb_sym name; const char *str; mrb_int len; - mrb_sym osym = mrb_intern_lit(mrb, "__outer__"); - outer = mrb_obj_iv_get(mrb, (struct RObject*)c, osym); - if (mrb_nil_p(outer)) return outer; - name = find_class_sym(mrb, mrb_class_ptr(outer), c); + if (detect_outer_loop(mrb, c)) return mrb_nil_value(); + outer = outer_class(mrb, c); + if (outer == NULL) return mrb_nil_value(); + name = find_class_sym(mrb, outer, c); 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); mrb_str_cat_cstr(mrb, path, str); mrb_str_cat_cstr(mrb, path, "::"); str = mrb_sym2name_len(mrb, name, &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); mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); return path; |
