From: "Eregon (Benoit Daloze) via ruby-core" Date: 2026-11-09T16:29:39+00:00 Subject: [ruby-core:127385] [Ruby Bug#22524] Calling a shareable Proc overwrites $~ and $_ of a Thread.new/Fiber.new block Issue #22524 has been reported by Eregon (Benoit Daloze). ---------------------------------------- Bug #22524: Calling a shareable Proc overwrites $~ and $_ of a Thread.new/Fiber.new block https://bugs.ruby-lang.org/issues/22524 * Author: Eregon (Benoit Daloze) * Status: Open * ruby -v: ruby 4.1.0dev (2026-11-09T15:47:20Z master 7e5d882817) +PRISM [arm64-darwin25] * Backport: 3.3: DONTNEED, 3.4: DONTNEED, 4.0: DONTNEED ---------------------------------------- Calling a shareable Proc which sets `$~` or `$_` directly from the block of `Thread.new` or `Fiber.new` overwrites the `$~` and `$_` of that block: ```ruby set = Ractor.shareable_proc { |s| s =~ /(.)/; $_ = s; nil } p Thread.new { $_ = "line"; "z" =~ /(z)/; set.("a"); [$~[1], $_] }.value # => ["z", "line"] p Fiber.new { $_ = "line"; "z" =~ /(z)/; set.("b"); [$~[1], $_] }.resume # => ["z", "line"] def m = ($_ = "line"; "z" =~ /(z)/; SET.("c"); [$~[1], $_]) SET = set p m # => ["z", "line"] ``` ``` $ ruby -v svar.rb ruby 4.1.0dev (2026-11-09T15:47:20Z master 7e5d882817) +PRISM [arm64-darwin25] ["a", "a"] ["b", "b"] ["z", "line"] ``` Ruby 4.0.7 prints `["z", "line"]` three times, so this is a regression. ## Cause Since 65424e1791 (GC: per-Ractor local GC), the special variables of a shareable Proc are kept per execution context (so per Fiber) instead of in its environment. That fixed a real problem: the environment of a shareable Proc can be used by several Ractors at once, so its `$~` was shared mutable state across Ractors. But they are kept in `ec->root_svar`, which also holds the special variables of the root frame of the Fiber or Thread, that is, its block. So calling a shareable Proc from that block overwrites them, as above. Calls from methods or from the main script are not affected, because those frames store their special variables in their own environment. ## Fix PR: https://github.com/ruby/ruby/pull/19804 The fix uses a separate per-execution-context slot, `ec->isolated_svar`, for the special variables of shareable Procs. They are still per Fiber, but no longer alias the root frame. Shareable Procs still share them with each other on the same Fiber. Truly per-call special variables would require saving and restoring them around each call of a shareable Proc, which seems too invasive for this bug fix. This also matters for https://github.com/ruby/ruby/pull/19801 (making the body of `define_method` shareable when possible): without this fix, a `define_method` method using a regexp would overwrite `$~` of a `Thread.new`/`Fiber.new` block calling it directly. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/