Bug #22293
open`String#unicode_normalize` does not work in non-main Ractor
Description
This fails consistently since Ruby 3.0 (except for using #take instead of #value).
$ ruby -v -W:no-ex -e 'p Ractor.new{"aaa".unicode_normalize}.value'
ruby 4.1.0dev (2026-09-04T13:17:34Z master 3643154e6d) +PRISM [arm64-darwin25]
#<Thread:0x0000000123bf0008 run> terminated with exception (report_on_exception is true):
/opt/local/lib/ruby/4.1.0+4/unicode_normalize/normalize.rb:138:in 'UnicodeNormalize.normalize': can not access non-shareable objects in constant UnicodeNormalize::NF_HASH_C by non-main ractor. (Ractor::IsolationError)
from -e:1:in 'String#unicode_normalize'
from -e:1:in 'block in <main>'
-e:1:in 'Ractor#value': thrown by remote Ractor. (Ractor::RemoteError)
from -e:1:in '<main>'
/opt/local/lib/ruby/4.1.0+4/unicode_normalize/normalize.rb:138:in 'UnicodeNormalize.normalize': can not access non-shareable objects in constant UnicodeNormalize::NF_HASH_C by non-main ractor. (Ractor::IsolationError)
from -e:1:in 'String#unicode_normalize'
from -e:1:in 'block in <main>'
Updated by duerst (Martin Dürst) about 18 hours ago
Just some comments to hopefully help this issue move forward.
unicode_normalize uses two hashes, UnicodeNormalize::NF_HASH_C and UnicodeNormalize::NF_HASH_D. These hashes are used to cache results of composition (NF_HASH_C) or decomposition (NF_HASH_D). They are updated with default procs when a key is not found (i.e. when the result of a normalization operation isn't already in the hash, and therefore has to be calculated.)
As long as the default proc isn't triggered, using unicode_normalize in parallel in two different ractors (or threads, or fibers, or anything else of that sort) is fine. But when the default proc is executed, the hash can change.
If the two key for which the default proc is executed in parallel are the same, then resulting value will also be the same (because Unicode normalization is deterministic).
I do not know the implementation of Hash in detail. If it can be used in parallel in threads and the like, it should be possible to get unicode_normalize to work in all Ractors in parallel. Potentially, just declaring the involved hashes as sharable could be enough.