mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
Unshare arrays only when they become shareable
obj_traverse_i called rb_ary_cancel_sharing on every array it visited, before the traversal knew whether the object graph was shareable. So Ractor.shareable? modified frozen arrays even when it returned false. This commit moves rb_ary_cancel_sharing into mark_shareable, which runs only after the traversal succeeds. [Bug #22460]
This commit is contained in:
1 parent
9fa6602683
commit
0d83a93784
3 files changed
+18
-4
Notes:
git
2026-10-22 12:02:25 +00:00
No files matched your search
@@ -579,8 +579,8 @@ rb_ary_cancel_sharing(VALUE ary)
|
||||
else if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && len > ((shared_len = RARRAY_LEN(shared_root))>>1)) {
|
||||
rb_len_t shift = RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared_root);
|
||||
FL_UNSET_SHARED(ary);
|
||||
ARY_SET_PTR(ary, RARRAY_CONST_PTR(shared_root));
|
||||
ARY_SET_CAPA(ary, shared_len);
|
||||
ARY_SET_PTR_FORCE(ary, RARRAY_CONST_PTR(shared_root));
|
||||
ARY_SET_CAPA_FORCE(ary, shared_len);
|
||||
RARRAY_PTR_USE(ary, ptr, {
|
||||
MEMMOVE(ptr, ptr+shift, VALUE, len);
|
||||
});
|
||||
|
||||
@@ -1754,8 +1754,6 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
|
||||
|
||||
case T_ARRAY:
|
||||
{
|
||||
rb_ary_cancel_sharing(obj);
|
||||
|
||||
for (rb_len_t i = 0; i < RARRAY_LEN(obj); i++) {
|
||||
VALUE e = RARRAY_AREF(obj, i);
|
||||
if (obj_traverse_i(e, data)) return 1;
|
||||
@@ -2002,6 +2000,9 @@ mark_shareable(VALUE obj)
|
||||
if (RB_BUILTIN_TYPE(obj) == T_STRING) {
|
||||
rb_str_make_independent(obj);
|
||||
}
|
||||
else if (RB_BUILTIN_TYPE(obj) == T_ARRAY) {
|
||||
rb_ary_cancel_sharing(obj);
|
||||
}
|
||||
|
||||
rb_obj_set_shareable_no_assert(obj);
|
||||
return traverse_cont;
|
||||
|
||||
@@ -955,6 +955,19 @@ class TestRactor < Test::Unit::TestCase
|
||||
RUBY
|
||||
end
|
||||
|
||||
# [Bug #22460] Ractor.shareable? must not replace the buffer of a frozen shared array.
|
||||
def test_shareable_p_keeps_frozen_shared_array_buffer
|
||||
assert_ractor(<<~'RUBY')
|
||||
o = Object.new
|
||||
a = Array.new(200) { it }
|
||||
a[50] = o
|
||||
b = a.pop(150)
|
||||
o.define_singleton_method(:to_s) { Ractor.shareable?(b); "x" }
|
||||
b.freeze
|
||||
assert_nothing_raised { assert_equal "x 51", "%1$s %2$s" % b }
|
||||
RUBY
|
||||
end
|
||||
|
||||
# Ractor::Port.new must not deadlock under GC.stress (regression guard for a stress GC
|
||||
# triggered by malloc while the ractor lock is held).
|
||||
def test_port_new_under_gc_stress
|
||||
|
||||
Reference in new issue
Block a user