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.
This commit is contained in:
parent
a271acf822
commit
05b1944c53
Notes:
git
2022-02-10 10:33:06 +09:00
@ -712,7 +712,7 @@ iow_internal_object_id(VALUE self)
|
|||||||
|
|
||||||
struct rof_data {
|
struct rof_data {
|
||||||
VALUE refs;
|
VALUE refs;
|
||||||
VALUE internals;
|
VALUE values;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -723,11 +723,15 @@ reachable_object_from_i(VALUE obj, void *data_ptr)
|
|||||||
VALUE val = obj;
|
VALUE val = obj;
|
||||||
|
|
||||||
if (rb_objspace_markable_object_p(obj)) {
|
if (rb_objspace_markable_object_p(obj)) {
|
||||||
|
if (NIL_P(rb_hash_lookup(data->refs, key))) {
|
||||||
|
rb_hash_aset(data->refs, key, Qtrue);
|
||||||
|
|
||||||
if (rb_objspace_internal_object_p(obj)) {
|
if (rb_objspace_internal_object_p(obj)) {
|
||||||
val = iow_newobj(obj);
|
val = iow_newobj(obj);
|
||||||
rb_ary_push(data->internals, val);
|
|
||||||
}
|
}
|
||||||
rb_hash_aset(data->refs, key, val);
|
|
||||||
|
rb_ary_push(data->values, val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,12 +795,12 @@ reachable_objects_from(VALUE self, VALUE obj)
|
|||||||
obj = (VALUE)DATA_PTR(obj);
|
obj = (VALUE)DATA_PTR(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.refs = rb_ident_hash_new();
|
data.refs = rb_obj_hide(rb_ident_hash_new());
|
||||||
data.internals = rb_ary_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 {
|
else {
|
||||||
return Qnil;
|
return Qnil;
|
||||||
|
@ -140,6 +140,18 @@ class TestObjSpace < Test::Unit::TestCase
|
|||||||
end;
|
end;
|
||||||
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
|
def test_reachable_objects_from_root
|
||||||
root_objects = ObjectSpace.reachable_objects_from_root
|
root_objects = ObjectSpace.reachable_objects_from_root
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user