Pin values in the finalizer table

When finalizers run (in `rb_objspace_call_finalizer`) the table is
copied to a linked list that is not managed by the GC.  If compaction
runs, the references in the linked list can go bad.

Finalizer table shouldn't be used frequently, so lets pin references in
the table so that the linked list in `rb_objspace_call_finalizer` is
safe.
This commit is contained in:
Aaron Patterson 2020-09-18 10:50:27 -07:00 committed by Aaron Patterson
parent 6dd257ed1e
commit 1a9dd31910
Notes: git 2020-09-19 04:32:35 +09:00

16
gc.c
View file

@ -5046,11 +5046,19 @@ mark_set(rb_objspace_t *objspace, st_table *tbl)
st_foreach(tbl, mark_key, (st_data_t)objspace);
}
static int
pin_value(st_data_t key, st_data_t value, st_data_t data)
{
rb_objspace_t *objspace = (rb_objspace_t *)data;
gc_mark_and_pin(objspace, (VALUE)value);
return ST_CONTINUE;
}
static void
mark_finalizer_tbl(rb_objspace_t *objspace, st_table *tbl)
{
if (!tbl) return;
st_foreach(tbl, mark_value, (st_data_t)objspace);
st_foreach(tbl, pin_value, (st_data_t)objspace);
}
void
@ -7846,11 +7854,6 @@ gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
case T_RATIONAL:
case T_NODE:
case T_CLASS:
if (FL_TEST(obj, FL_FINALIZE)) {
if (st_is_member(finalizer_table, obj)) {
return FALSE;
}
}
return RVALUE_MARKED(obj) && !RVALUE_PINNED(obj);
default:
@ -8748,7 +8751,6 @@ gc_update_references(rb_objspace_t * objspace)
gc_update_tbl_refs(objspace, objspace->obj_to_id_tbl);
gc_update_table_refs(objspace, objspace->id_to_obj_tbl);
gc_update_table_refs(objspace, global_symbols.str_sym);
gc_update_table_refs(objspace, finalizer_table);
}
static VALUE type_sym(size_t type);