mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Revert self-referencing finalizer warning [Feature #15974]
It has caused CI failures. *d0cd0866d8
Disable GC during rb_objspace_reachable_object_p *89cef1c56b
Version guard for [Feature #15974] *796eeb6339
. Fix up [Feature #15974] *928260c2a6
. Warn in verbose mode on defining a finalizer that captures the object
This commit is contained in:
parent
5d9e91afe0
commit
23c92b6f82
3 changed files with 3 additions and 121 deletions
64
gc.c
64
gc.c
|
@ -2954,8 +2954,6 @@ should_be_finalizable(VALUE obj)
|
|||
rb_check_frozen(obj);
|
||||
}
|
||||
|
||||
static int rb_objspace_reachable_object_p(VALUE obj, VALUE root);
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ObjectSpace.define_finalizer(obj, aProc=proc())
|
||||
|
@ -2965,10 +2963,6 @@ static int rb_objspace_reachable_object_p(VALUE obj, VALUE root);
|
|||
* as an argument to <i>aProc</i>. If <i>aProc</i> is a lambda or
|
||||
* method, make sure it can be called with a single argument.
|
||||
*
|
||||
* In verbose mode (<code>-w</code>) a warning will be issued if
|
||||
* the object is reachable from <i>aProc</i>, which may prevent
|
||||
* finalization.
|
||||
*
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
|
@ -2985,11 +2979,6 @@ define_final(int argc, VALUE *argv, VALUE os)
|
|||
should_be_callable(block);
|
||||
}
|
||||
|
||||
if (RTEST(ruby_verbose)) {
|
||||
if (rb_objspace_reachable_object_p(obj, block))
|
||||
rb_warn("object is reachable from finalizer - it may never be run");
|
||||
}
|
||||
|
||||
return define_final0(obj, block);
|
||||
}
|
||||
|
||||
|
@ -9337,59 +9326,6 @@ rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE,
|
|||
POP_MARK_FUNC_DATA();
|
||||
}
|
||||
|
||||
struct reachable_object_data {
|
||||
VALUE obj;
|
||||
VALUE set;
|
||||
};
|
||||
|
||||
static void
|
||||
reachable_object_callback(VALUE child, void *dp)
|
||||
{
|
||||
struct reachable_object_data *data = dp;
|
||||
if (child == data->obj) {
|
||||
rb_throw_obj(data->set, Qtrue);
|
||||
}
|
||||
|
||||
// Maintain a set of objects already searched, so that we don't follow a cycle
|
||||
if (rb_hash_lookup2(data->set, child, Qfalse))
|
||||
return;
|
||||
rb_hash_aset(data->set, child, Qtrue);
|
||||
|
||||
rb_objspace_reachable_objects_from(child, reachable_object_callback, data);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
call_reachable_object(RB_BLOCK_CALL_FUNC_ARGLIST(set, arg))
|
||||
{
|
||||
struct reachable_object_data *data = (void *)arg;
|
||||
VALUE obj = data->set;
|
||||
data->set = rb_obj_hide(set);
|
||||
gc_mark_children(&rb_objspace, obj);
|
||||
rb_hash_clear(set);
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
static int
|
||||
rb_objspace_reachable_object_p(VALUE obj, VALUE root)
|
||||
{
|
||||
rb_objspace_t *objspace = &rb_objspace;
|
||||
int reachable = FALSE;
|
||||
if (is_markable_object(objspace, obj)) {
|
||||
struct reachable_object_data data = {obj, root};
|
||||
struct mark_func_data_struct mfd = {&data, reachable_object_callback};
|
||||
int prev_dont_gc = dont_gc;
|
||||
enum ruby_tag_type state;
|
||||
|
||||
dont_gc = TRUE;
|
||||
PUSH_MARK_FUNC_DATA(&mfd);
|
||||
reachable = RTEST(rb_catch_protect(rb_ident_hash_new(), call_reachable_object, (VALUE)&data, &state));
|
||||
POP_MARK_FUNC_DATA();
|
||||
dont_gc = prev_dont_gc;
|
||||
if (state) EC_JUMP_TAG(GET_EC(), state);
|
||||
}
|
||||
return reachable;
|
||||
}
|
||||
|
||||
/*
|
||||
------------------------ Extended allocator ------------------------
|
||||
*/
|
||||
|
|
|
@ -65,32 +65,4 @@ describe "ObjectSpace.define_finalizer" do
|
|||
|
||||
ruby_exe(code).lines.sort.should == ["finalized1\n", "finalized2\n"]
|
||||
end
|
||||
|
||||
ruby_version_is "2.7" do
|
||||
it "warns in verbose mode if it is self-referencing" do
|
||||
code = <<-RUBY
|
||||
obj = "Test"
|
||||
handler = Proc.new { puts "finalized" }
|
||||
ObjectSpace.define_finalizer(obj, handler)
|
||||
exit 0
|
||||
RUBY
|
||||
|
||||
ruby_exe(code, :options => "-w", :args => "2>&1").should include("warning: object is reachable from finalizer - it may never be run")
|
||||
end
|
||||
|
||||
it "warns in verbose mode if it is indirectly self-referencing" do
|
||||
code = <<-RUBY
|
||||
def scoped(indirect)
|
||||
Proc.new { puts "finalized" }
|
||||
end
|
||||
obj = "Test"
|
||||
indirect = [obj]
|
||||
handler = scoped(indirect)
|
||||
ObjectSpace.define_finalizer(obj, handler)
|
||||
exit 0
|
||||
RUBY
|
||||
|
||||
ruby_exe(code, :options => "-w", :args => "2>&1").should include("warning: object is reachable from finalizer - it may never be run")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,7 +56,7 @@ End
|
|||
end
|
||||
|
||||
def test_finalizer
|
||||
assert_in_out_err(["-W0", "-e", <<-END], "", %w(:ok :ok :ok :ok))
|
||||
assert_in_out_err(["-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(["-W0"], code[""], ["finalized"])
|
||||
assert_in_out_err(["-W0"], code["private "], ["finalized"])
|
||||
assert_in_out_err([], code[""], ["finalized"])
|
||||
assert_in_out_err([], code["private "], ["finalized"])
|
||||
c = EnvUtil.labeled_class("C\u{3042}").new
|
||||
o = Object.new
|
||||
assert_raise_with_message(ArgumentError, /C\u{3042}/) {
|
||||
|
@ -131,32 +131,6 @@ 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
|
||||
|
|
Loading…
Reference in a new issue