@@ -1777,6 +1777,7 @@ rb_gc_pointer_to_heap_p(VALUE obj)
17771777static unsigned long long next_object_id = OBJ_ID_INITIAL ;
17781778static VALUE id_to_obj_value = 0 ;
17791779static st_table * id_to_obj_tbl = NULL ;
1780+ static bool id_to_obj_tbl_built = false;
17801781
17811782void
17821783rb_gc_obj_id_moved (VALUE obj )
@@ -1910,9 +1911,13 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id)
19101911 if (!id_to_obj_tbl ) {
19111912 rb_gc_vm_barrier (); // stop other ractors
19121913
1914+ // GC Must not trigger while we build the table, otherwise if we end
1915+ // up freeing an object that had an ID, we might try to delete it from
1916+ // the table even though it wasn't inserted yet.
19131917 id_to_obj_tbl = st_init_table (& object_id_hash_type );
19141918 id_to_obj_value = TypedData_Wrap_Struct (0 , & id_to_obj_tbl_type , id_to_obj_tbl );
19151919 rb_gc_impl_each_object (objspace , build_id_to_obj_i , (void * )id_to_obj_tbl );
1920+ id_to_obj_tbl_built = true;
19161921 }
19171922
19181923 VALUE obj ;
@@ -1941,7 +1946,10 @@ obj_free_object_id(VALUE obj)
19411946 RUBY_ASSERT (FIXNUM_P (obj_id ) || RB_TYPE_P (obj , T_BIGNUM ));
19421947
19431948 if (!st_delete (id_to_obj_tbl , (st_data_t * )& obj_id , NULL )) {
1944- rb_bug ("Object ID seen, but not in id_to_obj table: object_id=%llu object=%s" , NUM2ULL (obj_id ), rb_obj_info (obj ));
1949+ // If we're currently building the table then it's not a bug
1950+ if (id_to_obj_tbl_built ) {
1951+ rb_bug ("Object ID seen, but not in id_to_obj table: object_id=%llu object=%s" , NUM2ULL (obj_id ), rb_obj_info (obj ));
1952+ }
19451953 }
19461954 }
19471955 }
0 commit comments