From: merch-redmine@... Date: 2021-04-07T19:27:09+00:00 Subject: [ruby-core:103279] [Ruby master Bug#13876] Tempfile's finalizer can be interrupted by a Timeout exception which can cause the process to hang Issue #13876 has been updated by jeremyevans0 (Jeremy Evans). This is still a problem in the master branch. Possible solutions: 1. Run finalizers in a separate thread instead of the main thread. 2. Mark when thread is running finalizers. Mark exceptions added by `Thread#raise`. When a thread is checking pending interrupts, if it is running finalizers, ignore interrupts added by `Thread#raise`, so that the delivery of the exceptions is delayed until the thread is no longer running finalizers. 3. Mark when thread is running finalizers. Do not check for pending interrupts when running finalizers. 4. Remove `Thread#raise`. Option 4 is the simplest to implement, but it is not backwards compatible and I don't think it would be acceptable. I've a pull request for option 3, since it was fairly simple to implement: https://github.com/ruby/ruby/pull/4366 I think that the option 1 would be the most robust approach, but it requires an extra thread. ---------------------------------------- Bug #13876: Tempfile's finalizer can be interrupted by a Timeout exception which can cause the process to hang https://bugs.ruby-lang.org/issues/13876#change-91365 * Author: jrafanie (Joe Rafaniello) * Status: Open * Priority: Normal * ruby -v: ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin15] * Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN ---------------------------------------- Ruby hangs if a Timeout is raised when a Tempfile's finalizer is run. This also happens on ruby 2.3.4 on OSX. I could only recreate this on linux once but not reliably. Maybe the finalizer runs at a different and unpredictable time on Linux. See the following script: ```ruby require 'tempfile' require 'timeout' Tempfile.new("x") # this empty method is needed for some reason, maybe scope/GC related def stuff "" end 2.times do |i| begin Timeout.timeout(1e-9) do loop do begin "result" ensure end end end rescue Timeout::Error end end ``` When run, I get the following output and it hangs ~4 out of 5 times on OSX: ``` $ ruby -d test.rb Exception `LoadError' at /Users/joerafaniello/.rubies/ruby-2.4.1/lib/ruby/2.4.0/rubygems.rb:1345 - cannot load such file -- rubygems/defaults/operating_system Exception `LoadError' at /Users/joerafaniello/.rubies/ruby-2.4.1/lib/ruby/2.4.0/rubygems.rb:1354 - cannot load such file -- rubygems/defaults/ruby removing /var/folders/fq/blrz820d3qz7nm7vj8mbtfs40000gq/T/x20170906-72981-1ttdgpr... ``` When it doesn't hang (~1 in 5 tries), it looks like this (the exception seems to be raised after the file cleanup is done): ``` $ ruby -d test.rb Exception `LoadError' at /Users/joerafaniello/.rubies/ruby-2.4.1/lib/ruby/2.4.0/rubygems.rb:1345 - cannot load such file -- rubygems/defaults/operating_system Exception `LoadError' at /Users/joerafaniello/.rubies/ruby-2.4.1/lib/ruby/2.4.0/rubygems.rb:1354 - cannot load such file -- rubygems/defaults/ruby removing /var/folders/fq/blrz820d3qz7nm7vj8mbtfs40000gq/T/x20170906-72963-164cw8j... done Exception `Timeout::Error' at /Users/joerafaniello/.rubies/ruby-2.4.1/lib/ruby/2.4.0/timeout.rb:114 - execution expired Exception `Timeout::Error' at /Users/joerafaniello/.rubies/ruby-2.4.1/lib/ruby/2.4.0/timeout.rb:114 - execution expired ``` When it hangs, it seems to be this code: https://github.com/ruby/ruby/blob/0f25c6d7d59ff9744d1ca5dc908cc12c8ce79e25/lib/tempfile.rb#L253-L261 -- https://bugs.ruby-lang.org/ Unsubscribe: