summaryrefslogtreecommitdiff
path: root/class.c
diff options
context:
space:
mode:
authorLuke Gruber <luke.gruber@shopify.com>2025-12-18 12:37:27 -0500
committerGitHub <noreply@github.com>2025-12-18 12:37:27 -0500
commitbfd28d581c524c7a7df877f2425de9fdd8de161a (patch)
treeed9d77592680e0d2f5b1a28e273282cb6fb06296 /class.c
parentf133ebb2db664801f87efa98aa91d610d194b700 (diff)
make rb_singleton_class ractor safe (#15591)
Since singleton classes are created lazily, we need to make sure that we lock around their creation. Unfortunately, that means we need to lock around every shareable object's call to `singleton_class`, including classes and modules.
Diffstat (limited to 'class.c')
-rw-r--r--class.c37
1 files changed, 23 insertions, 14 deletions
diff --git a/class.c b/class.c
index 9716ba07da..840bdeb0c2 100644
--- a/class.c
+++ b/class.c
@@ -30,6 +30,7 @@
#include "internal/variable.h"
#include "ruby/st.h"
#include "vm_core.h"
+#include "ruby/ractor.h"
#include "yjit.h"
#include "zjit.h"
@@ -2823,7 +2824,7 @@ rb_special_singleton_class(VALUE obj)
* consistency of the metaclass hierarchy.
*/
static VALUE
-singleton_class_of(VALUE obj)
+singleton_class_of(VALUE obj, bool ensure_eigenclass)
{
VALUE klass;
@@ -2851,13 +2852,26 @@ singleton_class_of(VALUE obj)
}
}
- klass = METACLASS_OF(obj);
- if (!(RCLASS_SINGLETON_P(klass) &&
- RCLASS_ATTACHED_OBJECT(klass) == obj)) {
- klass = rb_make_metaclass(obj, klass);
+ bool needs_lock = rb_multi_ractor_p() && rb_ractor_shareable_p(obj);
+ unsigned int lev;
+ if (needs_lock) {
+ RB_VM_LOCK_ENTER_LEV(&lev);
+ }
+ {
+ klass = METACLASS_OF(obj);
+ if (!(RCLASS_SINGLETON_P(klass) &&
+ RCLASS_ATTACHED_OBJECT(klass) == obj)) {
+ klass = rb_make_metaclass(obj, klass);
+ }
+ RB_FL_SET_RAW(klass, RB_OBJ_FROZEN_RAW(obj));
+ if (ensure_eigenclass && RB_TYPE_P(obj, T_CLASS)) {
+ /* ensures an exposed class belongs to its own eigenclass */
+ (void)ENSURE_EIGENCLASS(klass);
+ }
+ }
+ if (needs_lock) {
+ RB_VM_LOCK_LEAVE_LEV(&lev);
}
-
- RB_FL_SET_RAW(klass, RB_OBJ_FROZEN_RAW(obj));
return klass;
}
@@ -2900,12 +2914,7 @@ rb_singleton_class_get(VALUE obj)
VALUE
rb_singleton_class(VALUE obj)
{
- VALUE klass = singleton_class_of(obj);
-
- /* ensures an exposed class belongs to its own eigenclass */
- if (RB_TYPE_P(obj, T_CLASS)) (void)ENSURE_EIGENCLASS(klass);
-
- return klass;
+ return singleton_class_of(obj, true);
}
/*!
@@ -2923,7 +2932,7 @@ rb_singleton_class(VALUE obj)
void
rb_define_singleton_method(VALUE obj, const char *name, VALUE (*func)(ANYARGS), int argc)
{
- rb_define_method(singleton_class_of(obj), name, func, argc);
+ rb_define_method(singleton_class_of(obj, false), name, func, argc);
}
#ifdef rb_define_module_function