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

ruby-changes:71137

From: John <ko1@a...>
Date: Thu, 10 Feb 2022 10:32:57 +0900 (JST)
Subject: [ruby-changes:71137] 05b1944c53 (master): objspace: Hide identhash containing internal objs

https://git.ruby-lang.org/ruby.git/commit/?id=05b1944c53

From 05b1944c53205ffd8c11f1ec2ae6fd48485b55b1 Mon Sep 17 00:00:00 2001
From: John Hawthorn <john@h...>
Date: Wed, 9 Feb 2022 12:14:51 -0800
Subject: objspace: Hide identhash containing internal objs

Inside ObjectSpace.reachable_objects_from we keep an internal identhash
in order to de-duplicate reachable objects when wrapping them as
InternalObject. Previously this hash was not hidden, making it possible
to leak references to those internal objects to Ruby if using
ObjectSpace.each_object.

This commit solves this by hiding the hash. To simplify collection of
values, we instead now just use the hash as a set of visited objects,
and collect an Array (not hidden) of values to be returned.
---
 ext/objspace/objspace.c        | 34 +++++++++++++++++++---------------
 test/objspace/test_objspace.rb | 12 ++++++++++++
 2 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c
index ad5bbe7d0c..d33dfeb80a 100644
--- a/ext/objspace/objspace.c
+++ b/ext/objspace/objspace.c
@@ -712,7 +712,7 @@ iow_internal_object_id(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace.c#L712
 
 struct rof_data {
     VALUE refs;
-    VALUE internals;
+    VALUE values;
 };
 
 static void
@@ -723,11 +723,15 @@ reachable_object_from_i(VALUE obj, void *data_ptr) https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace.c#L723
     VALUE val = obj;
 
     if (rb_objspace_markable_object_p(obj)) {
-	if (rb_objspace_internal_object_p(obj)) {
-	    val = iow_newobj(obj);
-	    rb_ary_push(data->internals, val);
-	}
-	rb_hash_aset(data->refs, key, val);
+        if (NIL_P(rb_hash_lookup(data->refs, key))) {
+            rb_hash_aset(data->refs, key, Qtrue);
+
+            if (rb_objspace_internal_object_p(obj)) {
+                val = iow_newobj(obj);
+            }
+
+            rb_ary_push(data->values, val);
+        }
     }
 }
 
@@ -785,21 +789,21 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/ext/objspace/objspace.c#L789
 reachable_objects_from(VALUE self, VALUE obj)
 {
     if (rb_objspace_markable_object_p(obj)) {
-	struct rof_data data;
+        struct rof_data data;
 
-	if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
-	    obj = (VALUE)DATA_PTR(obj);
-	}
+        if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
+            obj = (VALUE)DATA_PTR(obj);
+        }
 
-	data.refs = rb_ident_hash_new();
-	data.internals = rb_ary_new();
+        data.refs = rb_obj_hide(rb_ident_hash_new());
+        data.values = rb_ary_new();
 
-	rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data);
+        rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data);
 
-        return rb_funcall(data.refs, rb_intern("values"), 0);
+        return data.values;
     }
     else {
-	return Qnil;
+        return Qnil;
     }
 }
 
diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb
index 34d9dd76ec..781fb5b3c2 100644
--- a/test/objspace/test_objspace.rb
+++ b/test/objspace/test_objspace.rb
@@ -140,6 +140,18 @@ class TestObjSpace < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/objspace/test_objspace.rb#L140
     end;
   end
 
+  def test_reachable_objects_during_iteration
+    opts = %w[--disable-gem --disable=frozen-string-literal -robjspace]
+    assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}"
+    begin;
+      ObjectSpace.each_object{|o|
+        o.inspect
+        ObjectSpace.reachable_objects_from(Class)
+      }
+    end;
+  end
+
+
   def test_reachable_objects_from_root
     root_objects = ObjectSpace.reachable_objects_from_root
 
-- 
cgit v1.2.1


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

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