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/