[前][次][番号順一覧][スレッド一覧]

ruby-changes:58659

From: John <ko1@a...>
Date: Sat, 9 Nov 2019 05:41:31 +0900 (JST)
Subject: [ruby-changes:58659] 3b6954f8b9 (master): Fix passing actual object_id to finalizer

https://git.ruby-lang.org/ruby.git/commit/?id=3b6954f8b9

From 3b6954f8b9189f599e1f17636f8667a95ee94193 Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@h...>
Date: Thu, 7 Nov 2019 14:50:05 -0800
Subject: Fix passing actual object_id to finalizer

Previously we were passing the memory_id. This was broken previously if
compaction was run (which changes the memory_id) and now that object_id
is a monotonically increasing number it was always broken.

This commit fixes this by defering removal from the object_id table
until finalizers have run (for objects with finalizers) and also copying
the SEEN_OBJ_ID flag onto the zombie objects.

diff --git a/gc.c b/gc.c
index 7fd80a3..2ef9569 100644
--- a/gc.c
+++ b/gc.c
@@ -2484,7 +2484,7 @@ static inline void https://github.com/ruby/ruby/blob/trunk/gc.c#L2484
 make_zombie(rb_objspace_t *objspace, VALUE obj, void (*dfree)(void *), void *data)
 {
     struct RZombie *zombie = RZOMBIE(obj);
-    zombie->basic.flags = T_ZOMBIE;
+    zombie->basic.flags = T_ZOMBIE | (zombie->basic.flags & FL_SEEN_OBJ_ID);
     zombie->dfree = dfree;
     zombie->data = data;
     zombie->next = heap_pages_deferred_final;
@@ -2498,6 +2498,23 @@ make_io_zombie(rb_objspace_t *objspace, VALUE obj) https://github.com/ruby/ruby/blob/trunk/gc.c#L2498
     make_zombie(objspace, obj, (void (*)(void*))rb_io_fptr_finalize, fptr);
 }
 
+static void
+obj_free_object_id(rb_objspace_t *objspace, VALUE obj)
+{
+    VALUE id;
+
+    GC_ASSERT(FL_TEST(obj, FL_SEEN_OBJ_ID));
+    FL_UNSET(obj, FL_SEEN_OBJ_ID);
+
+    if (st_delete(objspace->obj_to_id_tbl, (st_data_t *)&obj, &id)) {
+        GC_ASSERT(id);
+        st_delete(objspace->id_to_obj_tbl, (st_data_t *)&id, NULL);
+    }
+    else {
+        rb_bug("Object ID seen, but not in mapping table: %s\n", obj_info(obj));
+    }
+}
+
 static int
 obj_free(rb_objspace_t *objspace, VALUE obj)
 {
@@ -2519,18 +2536,8 @@ obj_free(rb_objspace_t *objspace, VALUE obj) https://github.com/ruby/ruby/blob/trunk/gc.c#L2536
 	FL_UNSET(obj, FL_EXIVAR);
     }
 
-    if (FL_TEST(obj, FL_SEEN_OBJ_ID)) {
-        VALUE id;
-
-        FL_UNSET(obj, FL_SEEN_OBJ_ID);
-
-        if (st_delete(objspace->obj_to_id_tbl, (st_data_t *)&obj, &id)) {
-            GC_ASSERT(id);
-            st_delete(objspace->id_to_obj_tbl, (st_data_t *)&id, NULL);
-        }
-        else {
-            rb_bug("Object ID see, but not in mapping table: %s\n", obj_info(obj));
-        }
+    if (FL_TEST(obj, FL_SEEN_OBJ_ID) && !FL_TEST(obj, FL_FINALIZE)) {
+        obj_free_object_id(objspace, obj);
     }
 
 #if USE_RGENGC
@@ -3308,7 +3315,7 @@ run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table) https://github.com/ruby/ruby/blob/trunk/gc.c#L3315
 
     saved.safe = rb_safe_level();
     saved.errinfo = rb_errinfo();
-    saved.objid = nonspecial_obj_id(obj);
+    saved.objid = rb_obj_id(obj);
     saved.cfp = ec->cfp;
     saved.finished = 0;
 
@@ -3353,6 +3360,11 @@ finalize_list(rb_objspace_t *objspace, VALUE zombie) https://github.com/ruby/ruby/blob/trunk/gc.c#L3360
 
 	run_final(objspace, zombie);
 
+        GC_ASSERT(BUILTIN_TYPE(zombie) == T_ZOMBIE);
+        if (FL_TEST(zombie, FL_SEEN_OBJ_ID)) {
+            obj_free_object_id(objspace, zombie);
+        }
+
 	RZOMBIE(zombie)->basic.flags = 0;
         if (LIKELY(heap_pages_final_slots)) heap_pages_final_slots--;
 	page->final_slots--;
@@ -3595,7 +3607,7 @@ rb_objspace_garbage_object_p(VALUE obj) https://github.com/ruby/ruby/blob/trunk/gc.c#L3607
  */
 
 static VALUE
-id2ref(VALUE obj, VALUE objid)
+id2ref(VALUE objid)
 {
 #if SIZEOF_LONG == SIZEOF_VOIDP
 #define NUM2PTR(x) NUM2ULONG(x)
@@ -3637,6 +3649,12 @@ id2ref(VALUE obj, VALUE objid) https://github.com/ruby/ruby/blob/trunk/gc.c#L3649
 }
 
 static VALUE
+os_id2ref(VALUE os, VALUE objid)
+{
+    return id2ref(objid);
+}
+
+static VALUE
 rb_find_object_id(VALUE obj, VALUE (*get_heap_object_id)(VALUE))
 {
     if (STATIC_SYM_P(obj)) {
@@ -5946,7 +5964,7 @@ verify_internal_consistency_i(void *page_start, void *page_end, size_t stride, v https://github.com/ruby/ruby/blob/trunk/gc.c#L5964
 	}
 	else {
 	    if (BUILTIN_TYPE(obj) == T_ZOMBIE) {
-		GC_ASSERT(RBASIC(obj)->flags == T_ZOMBIE);
+		GC_ASSERT((RBASIC(obj)->flags & ~FL_SEEN_OBJ_ID) == T_ZOMBIE);
 		data->zombie_object_count++;
 	    }
 	}
@@ -10429,7 +10447,7 @@ wmap_finalize(RB_BLOCK_CALL_FUNC_ARGLIST(objid, self)) https://github.com/ruby/ruby/blob/trunk/gc.c#L10447
 
     TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
     /* Get reference from object id. */
-    obj = obj_id_to_ref(objid);
+    obj = id2ref(objid);
 
     /* obj is original referenced object and/or weak reference. */
     orig = (st_data_t)obj;
@@ -11840,7 +11858,7 @@ Init_GC(void) https://github.com/ruby/ruby/blob/trunk/gc.c#L11858
     rb_define_module_function(rb_mObjSpace, "define_finalizer", define_final, -1);
     rb_define_module_function(rb_mObjSpace, "undefine_finalizer", undefine_final, 1);
 
-    rb_define_module_function(rb_mObjSpace, "_id2ref", id2ref, 1);
+    rb_define_module_function(rb_mObjSpace, "_id2ref", os_id2ref, 1);
 
     rb_vm_register_special_exception(ruby_error_nomemory, rb_eNoMemError, "failed to allocate memory");
 
diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb
index f42e098..ef99f69 100644
--- a/test/ruby/test_gc.rb
+++ b/test/ruby/test_gc.rb
@@ -372,6 +372,14 @@ class TestGc < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_gc.rb#L372
     assert_empty(out)
   end
 
+  def test_finalizer_passed_object_id
+    assert_in_out_err(%w[--disable-gems], <<-EOS, ["true"], [])
+      o = Object.new
+      obj_id = o.object_id
+      ObjectSpace.define_finalizer(o, ->(id){ p id == obj_id })
+    EOS
+  end
+
   def test_verify_internal_consistency
     assert_nil(GC.verify_internal_consistency)
   end
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]