Bug #21649
closedRactors can access non-shareable object through singleton classes
Description
If we send a non-shareable object into a Ractor, it needs to be copied.
❯ ruby -W0 -e 'Ractor.new(p(Object.new)) { |o| p(o) }.join'
#<Object:0x00000001240f8cf8>
#<Object:0x00000001240f8870>
However we're able to instead smuggle it through a singleton class to unsafely get a mutable reference to the same object in both Ractors.
❯ ruby -W0 -e 'Ractor.new(p(Object.new).singleton_class) { |o| p(o.attached_object) }.join'
#<Object:0x0000000120768c40>
#<Object:0x0000000120768c40>
I think we should probably make singleton classes copy the shareability of their attached object.
Updated by ko1 (Koichi Sasada) about 1 month ago
- Status changed from Open to Closed
Applied in changeset git|17baadc072a84a02bb9bb3337efa86369d5832d1.
Make Class#attached_object respect Ractor isolation
A singleton class is shareable whatever it is attached to, so it can be sent
to another Ractor, and #attached_object then handed over the object itself:
$ ruby -W0 -e 'Ractor.new(p(Object.new).singleton_class) { |o| p o.attached_object }.join'
#<Object:0x0000000120768c40>
#<Object:0x0000000120768c40> # the same object in both Ractors
Raise Ractor::IsolationError when the attached object is unshareable and
lives in another Ractor's objspace. Guarding the reader covers every way a
singleton class is made: Object#clone (rb_singleton_class_clone_and_attach)
and the metaclass of a singleton class (make_metaclass) allocate one without
going through make_singleton_class, so making singleton classes unshareable
instead would have to catch all of them.
An object's owner is known from the objspace of its page, so a single-objspace
GC (mmtk) cannot make this check; the test is skipped there.
[Bug #21649]
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com