[ruby-core:124920] [Ruby Bug#21941] Local variable becomes nil when YJIT enabled mid-method with fork/signal/ensure
Issue #21941 has been reported by nicholasdower (Nick Dower). ---------------------------------------- Bug #21941: Local variable becomes nil when YJIT enabled mid-method with fork/signal/ensure https://bugs.ruby-lang.org/issues/21941 * Author: nicholasdower (Nick Dower) * Status: Open * ruby -v: ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin25] * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- The following code results in the `read` local variable becoming nil, even though it is never reassigned: ``` def run fork_safe = ->(t) { t } RubyVM::YJIT.enable read, wakeup = IO.pipe Signal.trap("SIGCHLD") { wakeup.write("!") } begin while true begin fork { exit } next if read.wait_readable rescue Interrupt end end ensure end end run ``` Error: ``` repro.rb:13:in 'Object#run': undefined method 'wait_readable' for nil (NoMethodError) next if read.wait_readable ^^^^^^^^^^^^^^ from repro.rb:21:in '<main>' ``` See also: https://github.com/puma/puma/issues/3620 https://github.com/Shopify/ruby/issues/625 -- https://bugs.ruby-lang.org/
Issue #21941 has been updated by byroot (Jean Boussier). Assignee set to jit Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN to 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED, 4.0: REQUIRED Reduced even further: ```ruby def run fork_safe = ->(t) { t } RubyVM::YJIT.enable read, wakeup = IO.pipe wakeup.write("!") begin while true begin next if read.wait_readable rescue Interrupt end end ensure end end run ``` ---------------------------------------- Bug #21941: Local variable becomes nil when YJIT enabled mid-method with fork/signal/ensure https://bugs.ruby-lang.org/issues/21941#change-116580 * Author: nicholasdower (Nick Dower) * Status: Open * Assignee: jit * ruby -v: ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin25] * Backport: 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED, 4.0: REQUIRED ---------------------------------------- The following code results in the `read` local variable becoming nil, even though it is never reassigned: ``` def run fork_safe = ->(t) { t } RubyVM::YJIT.enable read, wakeup = IO.pipe Signal.trap("SIGCHLD") { wakeup.write("!") } begin while true begin fork { exit } next if read.wait_readable rescue Interrupt end end ensure end end run ``` Error: ``` repro.rb:13:in 'Object#run': undefined method 'wait_readable' for nil (NoMethodError) next if read.wait_readable ^^^^^^^^^^^^^^ from repro.rb:21:in '<main>' ``` See also: https://github.com/puma/puma/issues/3620 https://github.com/Shopify/ruby/issues/625 -- https://bugs.ruby-lang.org/
Issue #21941 has been updated by byroot (Jean Boussier). Reduced some more, no IO or anything: ```ruby def run fork_safe = ->(t) { t } RubyVM::YJIT.enable i = 0 begin while i < 100 i += 1 p i begin next if i rescue Interrupt end end ensure end p :ok end run ``` ---------------------------------------- Bug #21941: Local variable becomes nil when YJIT enabled mid-method with fork/signal/ensure https://bugs.ruby-lang.org/issues/21941#change-116581 * Author: nicholasdower (Nick Dower) * Status: Open * Assignee: jit * ruby -v: ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin25] * Backport: 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED, 4.0: REQUIRED ---------------------------------------- The following code results in the `read` local variable becoming nil, even though it is never reassigned: ``` def run fork_safe = ->(t) { t } RubyVM::YJIT.enable read, wakeup = IO.pipe Signal.trap("SIGCHLD") { wakeup.write("!") } begin while true begin fork { exit } next if read.wait_readable rescue Interrupt end end ensure end end run ``` Error: ``` repro.rb:13:in 'Object#run': undefined method 'wait_readable' for nil (NoMethodError) next if read.wait_readable ^^^^^^^^^^^^^^ from repro.rb:21:in '<main>' ``` See also: https://github.com/puma/puma/issues/3620 https://github.com/Shopify/ruby/issues/625 -- https://bugs.ruby-lang.org/
Issue #21941 has been updated by ufuk (Ufuk Kayserilioglu). I have a fix for this here: https://github.com/ruby/ruby/pull/16306 ---------------------------------------- Bug #21941: Local variable becomes nil when YJIT enabled mid-method with fork/signal/ensure https://bugs.ruby-lang.org/issues/21941#change-116582 * Author: nicholasdower (Nick Dower) * Status: Open * Assignee: jit * ruby -v: ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin25] * Backport: 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED, 4.0: REQUIRED ---------------------------------------- The following code results in the `read` local variable becoming nil, even though it is never reassigned: ``` def run fork_safe = ->(t) { t } RubyVM::YJIT.enable read, wakeup = IO.pipe Signal.trap("SIGCHLD") { wakeup.write("!") } begin while true begin fork { exit } next if read.wait_readable rescue Interrupt end end ensure end end run ``` Error: ``` repro.rb:13:in 'Object#run': undefined method 'wait_readable' for nil (NoMethodError) next if read.wait_readable ^^^^^^^^^^^^^^ from repro.rb:21:in '<main>' ``` See also: https://github.com/puma/puma/issues/3620 https://github.com/Shopify/ruby/issues/625 -- https://bugs.ruby-lang.org/
Issue #21941 has been updated by k0kubun (Takashi Kokubun). Backport changed from 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED, 4.0: REQUIRED to 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED, 4.0: DONE ruby_4_0 commit:8466e93b1d6eb85ad5952ab3a10575fa453e77e2. ---------------------------------------- Bug #21941: Local variable becomes nil when YJIT enabled mid-method with fork/signal/ensure https://bugs.ruby-lang.org/issues/21941#change-116713 * Author: nicholasdower (Nick Dower) * Status: Closed * Assignee: jit * ruby -v: ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin25] * Backport: 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED, 4.0: DONE ---------------------------------------- The following code results in the `read` local variable becoming nil, even though it is never reassigned: ``` def run fork_safe = ->(t) { t } RubyVM::YJIT.enable read, wakeup = IO.pipe Signal.trap("SIGCHLD") { wakeup.write("!") } begin while true begin fork { exit } next if read.wait_readable rescue Interrupt end end ensure end end run ``` Error: ``` repro.rb:13:in 'Object#run': undefined method 'wait_readable' for nil (NoMethodError) next if read.wait_readable ^^^^^^^^^^^^^^ from repro.rb:21:in '<main>' ``` See also: https://github.com/puma/puma/issues/3620 https://github.com/Shopify/ruby/issues/625 -- https://bugs.ruby-lang.org/
participants (4)
-
byroot (Jean Boussier) -
k0kubun (Takashi Kokubun) -
nicholasdower (Nick Dower) -
ufuk (Ufuk Kayserilioglu)