From 7448afccb32f78115c05af03421984aa2f2aaf58 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Thu, 5 May 2022 16:08:24 -0400 Subject: Fix potential GC issue while iterating over weak refs While walking over the list of subclasses for `include` and friends, we check whether the subclass is a garbage object. After the check, we allocate objects which might trigger GC and make the subclass garbage, even though before the allocation the subclass was not garbage. This is a sort of time-of-check-time-of-use issue. Fix this by saving the weak reference to a local variable, upgrading it to a strong reference while we do the allocation. It makes the code look slightly nicer even if it doesn't fix any runtime issues. --- class.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'class.c') diff --git a/class.c b/class.c index b41e1a37e8..e752cf87d9 100644 --- a/class.c +++ b/class.c @@ -1383,17 +1383,18 @@ rb_prepend_module(VALUE klass, VALUE module) /* During lazy sweeping, iclass->klass could be a dead object that * has not yet been swept. */ if (!rb_objspace_garbage_object_p(iclass->klass)) { - if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(iclass->klass)) { + const VALUE subclass = iclass->klass; + if (klass_had_no_origin && klass_origin_m_tbl == RCLASS_M_TBL(subclass)) { // backfill an origin iclass to handle refinements and future prepends - rb_id_table_foreach(RCLASS_M_TBL(iclass->klass), clear_module_cache_i, (void *)iclass->klass); - RCLASS_M_TBL(iclass->klass) = klass_m_tbl; - VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(iclass->klass)); - RCLASS_SET_SUPER(iclass->klass, origin); - RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(iclass->klass)); - RCLASS_SET_ORIGIN(iclass->klass, origin); + rb_id_table_foreach(RCLASS_M_TBL(subclass), clear_module_cache_i, (void *)subclass); + RCLASS_M_TBL(subclass) = klass_m_tbl; + VALUE origin = rb_include_class_new(klass_origin, RCLASS_SUPER(subclass)); + RCLASS_SET_SUPER(subclass, origin); + RCLASS_SET_INCLUDER(origin, RCLASS_INCLUDER(subclass)); + RCLASS_SET_ORIGIN(subclass, origin); RICLASS_SET_ORIGIN_SHARED_MTBL(origin); } - include_modules_at(iclass->klass, iclass->klass, module, FALSE); + include_modules_at(subclass, subclass, module, FALSE); } iclass = iclass->next; -- cgit v1.2.1