From 5ea9ade5fcd9e02706c1fd464166fa84fa908a14 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 16 Sep 2026 20:41:33 +0900 Subject: [PATCH 1/2] Ignore EACCES when unlinking a tempfile from the finalizer On Windows, File.unlink raises Errno::EACCES while another handle still holds the file open. Tempfile#unlink already ignores that, but FinalizerManager#call only rescued ENOENT, so the exception escaped from the GC finalizer and was reported on stderr. Co-Authored-By: Claude Fable 5.1 --- lib/tempfile.rb | 2 +- test/test_tempfile.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/tempfile.rb b/lib/tempfile.rb index 8b042b7..dedd98f 100644 --- a/lib/tempfile.rb +++ b/lib/tempfile.rb @@ -390,7 +390,7 @@ def call(object_id) $stderr.puts "removing #{@path}..." if $DEBUG begin File.unlink(@path) - rescue Errno::ENOENT + rescue Errno::ENOENT, Errno::EACCES end $stderr.puts "done" if $DEBUG end diff --git a/test/test_tempfile.rb b/test/test_tempfile.rb index 8077cc3..a43ba28 100644 --- a/test/test_tempfile.rb +++ b/test/test_tempfile.rb @@ -235,6 +235,20 @@ def test_finalizer_does_not_unlink_if_already_unlinked end end unless /mswin|mingw/ =~ RUBY_PLATFORM + def test_finalizer_ignores_eacces_on_unlink + assert_in_out_err("-r#{LIB_TEMPFILE_RB_PATH}", <<~'RUBY') do |(filename,*), (error,*)| + def File.unlink(*) + raise Errno::EACCES + end + file = Tempfile.new("foo") + puts file.path + RUBY + assert_file.exist?(filename) + File.unlink(filename) + assert_nil error + end + end + def test_close_does_not_make_path_nil t = tempfile("foo") t.close From 4ddbe9ed4cae3ee457a34217b559a4c9e340b647 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 25 Sep 2026 18:00:10 +0900 Subject: [PATCH 2/2] Stub File.unlink without redefining it in the tempfile test Redefining the method warns under RUBYOPT=-w, which CI uses, and the test expects nothing on stderr. Prepending a module leaves the original method in place. Co-Authored-By: Claude Opus 5.5 --- test/test_tempfile.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test_tempfile.rb b/test/test_tempfile.rb index a43ba28..91cb1a8 100644 --- a/test/test_tempfile.rb +++ b/test/test_tempfile.rb @@ -237,9 +237,11 @@ def test_finalizer_does_not_unlink_if_already_unlinked def test_finalizer_ignores_eacces_on_unlink assert_in_out_err("-r#{LIB_TEMPFILE_RB_PATH}", <<~'RUBY') do |(filename,*), (error,*)| - def File.unlink(*) - raise Errno::EACCES - end + File.singleton_class.prepend(Module.new do + def unlink(*) + raise Errno::EACCES + end + end) file = Tempfile.new("foo") puts file.path RUBY