1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Fix up [Feature #15974]

* Fixed warning condition
* Fixed function signature
* Use ident hash
This commit is contained in:
Nobuyoshi Nakada 2019-07-03 04:12:20 +09:00
parent 928260c2a6
commit 796eeb6339
No known key found for this signature in database
GPG key ID: 4BC7D6DF58D8DF60
2 changed files with 40 additions and 14 deletions

22
gc.c
View file

@ -2961,8 +2961,9 @@ struct should_not_capture_data {
}; };
static void static void
should_not_capture_callback(const VALUE child, struct should_not_capture_data *data) should_not_capture_callback(VALUE child, void *dp)
{ {
struct should_not_capture_data *data = dp;
if (child == data->obj) if (child == data->obj)
data->found = true; data->found = true;
@ -2970,22 +2971,20 @@ should_not_capture_callback(const VALUE child, struct should_not_capture_data *d
return; return;
// Maintain a set of objects already searched, so that we don't follow a cycle // Maintain a set of objects already searched, so that we don't follow a cycle
VALUE key = rb_obj_id(child); if (rb_hash_lookup2(data->set, child, Qfalse))
if (rb_hash_has_key(data->set, key))
return; return;
rb_hash_aset(data->set, key, Qtrue); rb_hash_aset(data->set, child, Qtrue);
rb_objspace_reachable_objects_from(child, (void (*)(unsigned long, void *)) &should_not_capture_callback, (void *)data); rb_objspace_reachable_objects_from(child, should_not_capture_callback, data);
} }
static void static void
should_not_capture(VALUE block, VALUE obj) should_not_capture(VALUE block, VALUE obj)
{ {
struct should_not_capture_data data; struct should_not_capture_data data = {obj, rb_ident_hash_new()};
data.obj = obj; rb_obj_hide(data.set);
data.set = rb_hash_new(); rb_objspace_reachable_objects_from(block, should_not_capture_callback, &data);
data.found = false; rb_hash_clear(data.set);
rb_objspace_reachable_objects_from(block, (void (*)(unsigned long, void *)) &should_not_capture_callback, (void *)&data);
if (data.found) if (data.found)
rb_warn("object is reachable from finalizer - it may never be run"); rb_warn("object is reachable from finalizer - it may never be run");
} }
@ -3019,8 +3018,9 @@ define_final(int argc, VALUE *argv, VALUE os)
should_be_callable(block); should_be_callable(block);
} }
if (ruby_verbose) if (RTEST(ruby_verbose)) {
should_not_capture(block, obj); should_not_capture(block, obj);
}
return define_final0(obj, block); return define_final0(obj, block);
} }

View file

@ -56,7 +56,7 @@ End
end end
def test_finalizer def test_finalizer
assert_in_out_err(["-e", <<-END], "", %w(:ok :ok :ok :ok), []) assert_in_out_err(["-W0", "-e", <<-END], "", %w(:ok :ok :ok :ok))
a = [] a = []
ObjectSpace.define_finalizer(a) { p :ok } ObjectSpace.define_finalizer(a) { p :ok }
b = a.dup b = a.dup
@ -76,8 +76,8 @@ End
ObjectSpace.define_finalizer([], fin) ObjectSpace.define_finalizer([], fin)
CODE CODE
end end
assert_in_out_err([], code[""], ["finalized"]) assert_in_out_err(["-W0"], code[""], ["finalized"])
assert_in_out_err([], code["private "], ["finalized"]) assert_in_out_err(["-W0"], code["private "], ["finalized"])
c = EnvUtil.labeled_class("C\u{3042}").new c = EnvUtil.labeled_class("C\u{3042}").new
o = Object.new o = Object.new
assert_raise_with_message(ArgumentError, /C\u{3042}/) { assert_raise_with_message(ArgumentError, /C\u{3042}/) {
@ -131,6 +131,32 @@ End
END END
end end
def test_self_referencing_finalizer
assert_separately(["-w"], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
obj = +"Test"
handler = proc {puts "finalized"}
assert_warning(/object is reachable from finalizer/) do
ObjectSpace.define_finalizer(obj, handler)
end
end;
end
def test_indirectly_self_referencing_finalizer
assert_separately(["-w"], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
def scoped(indirect)
proc {puts "finalized"}
end
obj = +"Test"
indirect = [obj]
handler = scoped(indirect)
assert_warning(/object is reachable from finalizer/) do
ObjectSpace.define_finalizer(obj, handler)
end
end;
end
def test_each_object def test_each_object
klass = Class.new klass = Class.new
new_obj = klass.new new_obj = klass.new