From 966fcb77e48328baf28c1d042d8da25ba181f262 Mon Sep 17 00:00:00 2001 From: Luke Gruber Date: Wed, 21 May 2025 11:32:49 -0400 Subject: [PATCH] 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. --- bootstraptest/test_ractor.rb | 10 ++++++++++ variable.c | 16 ++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index 6adb042f94..112f5aac4b 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -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 diff --git a/variable.c b/variable.c index 62dfe5844e..661a0ef04f 100644 --- a/variable.c +++ b/variable.c @@ -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