diff options
| author | Peter Zhu <peter@peterzhu.ca> | 2023-12-24 21:26:37 -0500 |
|---|---|---|
| committer | Peter Zhu <peter@peterzhu.ca> | 2023-12-24 22:13:49 -0500 |
| commit | b4efa4b7005efee484e61fbc6af9c652fee36db2 (patch) | |
| tree | 5c1556521231d47f2531417a9fc61451c2464bc5 | |
| parent | 1b5f3dd6a1a5d054e3fd5af10b5dc2f49e1046fc (diff) | |
Don't copy RUBY_FL_PROMOTED flag in rb_obj_setup
RUBY_FL_PROMOTED is used by the garbage collector to track when an
object becomes promoted to the old generation. rb_obj_setup must not
copy that flag over because then it may become out-of-sync with the age
of the object.
This fixes a bug in Method#clone where the cloned Method object may get
RUBY_FL_PROMOTED incorrectly set.
| -rw-r--r-- | object.c | 3 | ||||
| -rw-r--r-- | test/ruby/test_method.rb | 11 |
2 files changed, 13 insertions, 1 deletions
@@ -119,7 +119,8 @@ rb_obj_reveal(VALUE obj, VALUE klass) VALUE rb_obj_setup(VALUE obj, VALUE klass, VALUE type) { - RBASIC(obj)->flags = type; + VALUE ignored_flags = RUBY_FL_PROMOTED; + RBASIC(obj)->flags = (type & ~ignored_flags) | (RBASIC(obj)->flags & ignored_flags); RBASIC_SET_CLASS(obj, klass); return obj; } diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index 9f34164a77..b22dd9cbee 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -450,6 +450,17 @@ class TestMethod < Test::Unit::TestCase assert_equal(:bar, m.clone.bar) end + def test_clone_under_gc_compact_stress + EnvUtil.under_gc_compact_stress do + o = Object.new + def o.foo; :foo; end + m = o.method(:foo) + def m.bar; :bar; end + assert_equal(:foo, m.clone.call) + assert_equal(:bar, m.clone.bar) + end + end + def test_inspect o = Object.new def o.foo; end; line_no = __LINE__ |
