1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

[Bug #18627] Fix crash when including module

During lazy sweeping, the iclass could be a dead object that has not yet
been swept. However, the chain of superclasses of the iclass could
already have been swept (and become a new object), which would cause a
crash when trying to read the object.
This commit is contained in:
Peter Zhu 2022-03-16 15:46:40 -04:00
parent 634e0a97eb
commit 97426e15d7
Notes: git 2022-03-18 22:19:44 +09:00

48
class.c
View file

@ -1117,17 +1117,24 @@ rb_include_module(VALUE klass, VALUE module)
int do_include = 1; int do_include = 1;
while (iclass) { while (iclass) {
VALUE check_class = iclass->klass; VALUE check_class = iclass->klass;
while (check_class) { /* During lazy sweeping, iclass->klass could be a dead object that
if (RB_TYPE_P(check_class, T_ICLASS) && * has not yet been swept. */
(METACLASS_OF(check_class) == module)) { if (!rb_objspace_garbage_object_p(check_class)) {
do_include = 0; while (check_class) {
RUBY_ASSERT(!rb_objspace_garbage_object_p(check_class));
if (RB_TYPE_P(check_class, T_ICLASS) &&
(METACLASS_OF(check_class) == module)) {
do_include = 0;
}
check_class = RCLASS_SUPER(check_class);
}
if (do_include) {
include_modules_at(iclass->klass, RCLASS_ORIGIN(iclass->klass), module, TRUE);
} }
check_class = RCLASS_SUPER(check_class);
} }
if (do_include) {
include_modules_at(iclass->klass, RCLASS_ORIGIN(iclass->klass), module, TRUE);
}
iclass = iclass->next; iclass = iclass->next;
} }
} }
@ -1363,17 +1370,22 @@ rb_prepend_module(VALUE klass, VALUE module)
struct rb_id_table *klass_m_tbl = RCLASS_M_TBL(klass); struct rb_id_table *klass_m_tbl = RCLASS_M_TBL(klass);
struct rb_id_table *klass_origin_m_tbl = RCLASS_M_TBL(klass_origin); struct rb_id_table *klass_origin_m_tbl = RCLASS_M_TBL(klass_origin);
while (iclass) { while (iclass) {
if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(iclass->klass)) { /* During lazy sweeping, iclass->klass could be a dead object that
// backfill an origin iclass to handle refinements and future prepends * has not yet been swept. */
rb_id_table_foreach(RCLASS_M_TBL(iclass->klass), clear_module_cache_i, (void *)iclass->klass); if (!rb_objspace_garbage_object_p(iclass->klass)) {
RCLASS_M_TBL(iclass->klass) = klass_m_tbl; if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(iclass->klass)) {
VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(iclass->klass)); // backfill an origin iclass to handle refinements and future prepends
RCLASS_SET_SUPER(iclass->klass, origin); rb_id_table_foreach(RCLASS_M_TBL(iclass->klass), clear_module_cache_i, (void *)iclass->klass);
RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(iclass->klass)); RCLASS_M_TBL(iclass->klass) = klass_m_tbl;
RCLASS_SET_ORIGIN(iclass->klass, origin); VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(iclass->klass));
RICLASS_SET_ORIGIN_SHARED_MTBL(origin); RCLASS_SET_SUPER(iclass->klass, origin);
RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(iclass->klass));
RCLASS_SET_ORIGIN(iclass->klass, origin);
RICLASS_SET_ORIGIN_SHARED_MTBL(origin);
}
include_modules_at(iclass->klass, iclass->klass, module, FALSE);
} }
include_modules_at(iclass->klass, iclass->klass, module, FALSE);
iclass = iclass->next; iclass = iclass->next;
} }
} }