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
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)
data->found = true;
@ -2970,22 +2971,20 @@ should_not_capture_callback(const VALUE child, struct should_not_capture_data *d
return;
// Maintain a set of objects already searched, so that we don't follow a cycle
VALUE key = rb_obj_id(child);
if (rb_hash_has_key(data->set, key))
if (rb_hash_lookup2(data->set, child, Qfalse))
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
should_not_capture(VALUE block, VALUE obj)
{
struct should_not_capture_data data;
data.obj = obj;
data.set = rb_hash_new();
data.found = false;
rb_objspace_reachable_objects_from(block, (void (*)(unsigned long, void *)) &should_not_capture_callback, (void *)&data);
struct should_not_capture_data data = {obj, rb_ident_hash_new()};
rb_obj_hide(data.set);
rb_objspace_reachable_objects_from(block, should_not_capture_callback, &data);
rb_hash_clear(data.set);
if (data.found)
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);
}
if (ruby_verbose)
if (RTEST(ruby_verbose)) {
should_not_capture(block, obj);
}
return define_final0(obj, block);
}

View file

@ -56,7 +56,7 @@ End
end
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 = []
ObjectSpace.define_finalizer(a) { p :ok }
b = a.dup
@ -76,8 +76,8 @@ End
ObjectSpace.define_finalizer([], fin)
CODE
end
assert_in_out_err([], code[""], ["finalized"])
assert_in_out_err([], code["private "], ["finalized"])
assert_in_out_err(["-W0"], code[""], ["finalized"])
assert_in_out_err(["-W0"], code["private "], ["finalized"])
c = EnvUtil.labeled_class("C\u{3042}").new
o = Object.new
assert_raise_with_message(ArgumentError, /C\u{3042}/) {
@ -131,6 +131,32 @@ 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
klass = Class.new
new_obj = klass.new