From f6cbf499bc98b851034fffb49fcbb59d495f6f7b Mon Sep 17 00:00:00 2001 From: Luke Gruber Date: Tue, 20 May 2025 09:41:57 -0400 Subject: [PATCH] Fix Symbol#to_proc (rb_sym_to_proc) to be ractor safe In non-main ractors, don't use `sym_proc_cache`. It is not thread-safe to add to this array without a lock and also it leaks procs from one ractor to another. Instead, we create a new proc each time. If this results in poor performance we can come up with a solution later. Fixes [Bug #21354] --- bootstraptest/test_ractor.rb | 12 ++++++++++++ common.mk | 2 ++ proc.c | 34 +++++++++++++++++++--------------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index 914807246c..6adb042f94 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -2307,6 +2307,18 @@ assert_equal 'ok', %q{ 'ok' } +# Using Symbol#to_proc inside ractors +# [Bug #21354] +assert_equal 'ok', %q{ + :inspect.to_proc + Ractor.new do + # It should not use this cached proc, it should create a new one. If it used + # the cached proc, we would get a ractor_confirm_belonging error here. + :inspect.to_proc + end.take + 'ok' +} + # 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/common.mk b/common.mk index e8c4e8d40e..7719047fd7 100644 --- a/common.mk +++ b/common.mk @@ -13836,6 +13836,8 @@ proc.$(OBJEXT): {$(VPATH)}prism/diagnostic.h proc.$(OBJEXT): {$(VPATH)}prism/version.h proc.$(OBJEXT): {$(VPATH)}prism_compile.h proc.$(OBJEXT): {$(VPATH)}proc.c +proc.$(OBJEXT): {$(VPATH)}ractor.h +proc.$(OBJEXT): {$(VPATH)}ractor_core.h proc.$(OBJEXT): {$(VPATH)}ruby_assert.h proc.$(OBJEXT): {$(VPATH)}ruby_atomic.h proc.$(OBJEXT): {$(VPATH)}rubyparser.h diff --git a/proc.c b/proc.c index 0cf3fb69e6..c6568fe1a6 100644 --- a/proc.c +++ b/proc.c @@ -22,6 +22,7 @@ #include "method.h" #include "iseq.h" #include "vm_core.h" +#include "ractor_core.h" #include "yjit.h" const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase); @@ -1538,23 +1539,26 @@ rb_sym_to_proc(VALUE sym) long index; ID id; - if (!sym_proc_cache) { - sym_proc_cache = rb_ary_hidden_new(SYM_PROC_CACHE_SIZE * 2); - rb_vm_register_global_object(sym_proc_cache); - rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil); - } - id = SYM2ID(sym); - index = (id % SYM_PROC_CACHE_SIZE) << 1; - if (RARRAY_AREF(sym_proc_cache, index) == sym) { - return RARRAY_AREF(sym_proc_cache, index + 1); - } - else { - proc = sym_proc_new(rb_cProc, ID2SYM(id)); - RARRAY_ASET(sym_proc_cache, index, sym); - RARRAY_ASET(sym_proc_cache, index + 1, proc); - return proc; + if (rb_ractor_main_p()) { + index = (id % SYM_PROC_CACHE_SIZE) << 1; + if (!sym_proc_cache) { + sym_proc_cache = rb_ary_hidden_new(SYM_PROC_CACHE_SIZE * 2); + rb_vm_register_global_object(sym_proc_cache); + rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil); + } + if (RARRAY_AREF(sym_proc_cache, index) == sym) { + return RARRAY_AREF(sym_proc_cache, index + 1); + } + else { + proc = sym_proc_new(rb_cProc, ID2SYM(id)); + RARRAY_ASET(sym_proc_cache, index, sym); + RARRAY_ASET(sym_proc_cache, index + 1, proc); + return proc; + } + } else { + return sym_proc_new(rb_cProc, ID2SYM(id)); } }