should not use rb_ary_modify()

ractor_copy() used rb_ary_modify() to make sure this array is not
sharing anything, but it also checks frozen flag. So frozen arrays
raises an error. To solve this issue, this patch introduces new
function rb_ary_cancel_sharing() which makes sure the array does not
share another array and it doesn't check frozen flag.
[Bug #17343]

A test is quoted from https://github.com/ruby/ruby/pull/3817
This commit is contained in:
Koichi Sasada 2020-12-01 11:14:36 +09:00
Родитель d2cfb5228a
Коммит 8247b8edde
4 изменённых файлов: 29 добавлений и 13 удалений

10
array.c
Просмотреть файл

@ -562,9 +562,8 @@ rb_ary_modify_check(VALUE ary)
}
void
rb_ary_modify(VALUE ary)
rb_ary_cancel_sharing(VALUE ary)
{
rb_ary_modify_check(ary);
if (ARY_SHARED_P(ary)) {
long shared_len, len = RARRAY_LEN(ary);
VALUE shared_root = ARY_SHARED_ROOT(ary);
@ -603,6 +602,13 @@ rb_ary_modify(VALUE ary)
ary_verify(ary);
}
void
rb_ary_modify(VALUE ary)
{
rb_ary_modify_check(ary);
rb_ary_cancel_sharing(ary);
}
static VALUE
ary_ensure_room_for_push(VALUE ary, long add_len)
{

Просмотреть файл

@ -1022,6 +1022,13 @@ assert_equal 'can not make a Proc shareable because it accesses outer variables
end
}
# Ractor deep copies frozen objects
assert_equal '[true, false]', %q{
Ractor.new([[]].freeze) { |ary|
[ary.frozen?, ary.first.frozen? ]
}.take
}
###
### Synchronization tests
###

Просмотреть файл

@ -29,6 +29,8 @@ VALUE rb_ary_tmp_new_fill(long capa);
VALUE rb_ary_at(VALUE, VALUE);
size_t rb_ary_memsize(VALUE);
VALUE rb_to_array_type(VALUE obj);
void rb_ary_cancel_sharing(VALUE ary);
static inline VALUE rb_ary_entry_internal(VALUE ary, long offset);
static inline bool ARY_PTR_USING_P(VALUE ary);
static inline void RARY_TRANSIENT_SET(VALUE ary);

Просмотреть файл

@ -2314,7 +2314,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_ARRAY:
{
rb_ary_modify(obj);
rb_ary_cancel_sharing(obj);
#if USE_TRANSIENT_HEAP
if (data->move) rb_ary_transient_heap_evacuate(obj, TRUE);
#endif
@ -2537,7 +2537,8 @@ copy_leave(VALUE obj, struct obj_traverse_replace_data *data)
return traverse_cont;
}
static VALUE ractor_copy(VALUE obj)
static VALUE
ractor_copy(VALUE obj)
{
VALUE val = rb_obj_traverse_replace(obj, copy_enter, copy_leave, false);
if (val != Qundef) {