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]
This commit is contained in:
Luke Gruber 2025-05-20 09:41:57 -04:00 committed by Jean Boussier
parent 97e774b95d
commit f6cbf499bc
Notes: git 2025-05-21 06:12:31 +00:00
3 changed files with 33 additions and 15 deletions

View File

@ -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

View File

@ -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

12
proc.c
View File

@ -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,15 +1539,15 @@ rb_sym_to_proc(VALUE sym)
long index;
ID id;
id = SYM2ID(sym);
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);
}
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);
}
@ -1556,6 +1557,9 @@ rb_sym_to_proc(VALUE sym)
RARRAY_ASET(sym_proc_cache, index + 1, proc);
return proc;
}
} else {
return sym_proc_new(rb_cProc, ID2SYM(id));
}
}
/*