lock vm around rb_free_generic_ivar

Currently, this can be reproduced by:

r = Ractor.new do
    a = [1, 2, 3]
    a.object_id
    a.dup # this frees the generic ivar for `object_id` on the copied object
    :done
end
r.take

In debug builds, this hits an assertion failure without this fix.
This commit is contained in:
Luke Gruber 2025-05-21 11:32:49 -04:00 committed by Nobuyoshi Nakada
parent 627a5ac53b
commit 966fcb77e4
Notes: git 2025-05-23 09:20:48 +00:00
2 changed files with 20 additions and 6 deletions

View File

@ -2319,6 +2319,16 @@ assert_equal 'ok', %q{
'ok'
}
# take vm lock when deleting generic ivars from the global table
assert_equal 'ok', %q{
Ractor.new do
a = [1, 2, 3]
a.object_id
a.dup # this deletes generic ivar on dupped object
'ok'
end.take
}
# There are some bugs in Windows with multiple threads in same ractor calling ractor actions
# Ex: https://github.com/ruby/ruby/actions/runs/14998660285/job/42139383905
unless /mswin/ =~ RUBY_PLATFORM

View File

@ -1273,15 +1273,19 @@ rb_free_generic_ivar(VALUE obj)
bool too_complex = rb_shape_obj_too_complex_p(obj);
if (st_delete(generic_fields_tbl_no_ractor_check(obj), &key, &value)) {
struct gen_fields_tbl *fields_tbl = (struct gen_fields_tbl *)value;
RB_VM_LOCK_ENTER();
{
if (st_delete(generic_fields_tbl_no_ractor_check(obj), &key, &value)) {
struct gen_fields_tbl *fields_tbl = (struct gen_fields_tbl *)value;
if (UNLIKELY(too_complex)) {
st_free_table(fields_tbl->as.complex.table);
if (UNLIKELY(too_complex)) {
st_free_table(fields_tbl->as.complex.table);
}
xfree(fields_tbl);
}
xfree(fields_tbl);
}
RB_VM_LOCK_LEAVE();
}
size_t