Issue #21926 has been updated by jhawthorn (John Hawthorn). Just for the record, this code should not hang and the fix is good, but the pattern in the reproduction isn't safe. The defined finalizer could potentially be run on any thread including the wait_thread, which would result in the error `Target thread must not be current thread (ThreadError)`. ---------------------------------------- Bug #21926: Thread#value on popen3 wait thread hangs in finalizer https://bugs.ruby-lang.org/issues/21926#change-116869 * Author: stevecrozz (Stephen Crosby) * Status: Closed * Assignee: luke-gru (Luke Gruber) * ruby -v: 3.3.7 * Backport: 3.2: UNKNOWN, 3.3: REQUIRED, 3.4: REQUIRED, 4.0: DONE ---------------------------------------- Calling Thread#value on an Open3.popen3 wait thread from a finalizer completes in Ruby 3.2 but hangs in Ruby 3.3+. See repro.rb below. When the Ruby process hangs in these conditions, it no longer responds to signals and it seems to be unable to run any other threads. This affects the schmooze gem (and potentially other code using Open3.popen3 with finalizers), causing test suites to hang intermittently. ``` ruby # repro.rb require 'open3' class ProcessWrapper def initialize @stdin, @stdout, @stderr, @wait_thread = Open3.popen3("cat") ObjectSpace.define_finalizer(self, self.class.make_finalizer(@stdin, @stdout, @stderr, @wait_thread)) end def self.make_finalizer(stdin, stdout, stderr, wait_thread) proc do stdin.close rescue nil stdout.close rescue nil stderr.close rescue nil wait_thread.value # Hangs here in Ruby 3.3+ end end end 100.times { ProcessWrapper.new } GC.stress = true 1000.times { Object.new } puts "done" ``` ## Environment - Linux x86_64 - Tested on Ruby 3.2.7, 3.3.7, 3.4.8 -- https://bugs.ruby-lang.org/