From d41370aec5370c96a7a1a62b1be84d21347901fc Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Tue, 22 Sep 2026 12:56:16 +0900 Subject: [PATCH] Fix crash in Dir#each/each_child/scan when closed If the Dir object is closed in the block of Dir#each/each_child/scan, then it will crash because dirp->dir will be a NULL pointer. The following script demonstrates the crash: d = Dir.open("/") d.each { d.close } --- dir.c | 2 ++ test/ruby/test_dir.rb | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/dir.c b/dir.c index 221fe3fffc16c6..9a1d41c0d3e913 100644 --- a/dir.c +++ b/dir.c @@ -1102,6 +1102,8 @@ dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE, struct dir_entry_args *), .dp = dp, }; (*each)(arg, path, &each_args); + /* the block may have closed dir */ + if (!dirp->dir) dir_closed(); } return dir; } diff --git a/test/ruby/test_dir.rb b/test/ruby/test_dir.rb index 2ac8b1dc1386f0..8ac37af0dc7234 100644 --- a/test/ruby/test_dir.rb +++ b/test/ruby/test_dir.rb @@ -237,6 +237,17 @@ def test_close assert_raise(IOError) { d.read } end + def test_each_with_close + d = Dir.open(@root) + assert_raise(IOError) { d.each { d.close } } + + d = Dir.open(@root) + assert_raise(IOError) { d.each_child { d.close } } + + d = Dir.open(@root) + assert_raise(IOError) { d.scan { |*| d.close } } + end + def test_glob assert_equal((%w(.) + ("a".."z").to_a).map{|f| File.join(@root, f) }, Dir.glob(File.join(@root, "*"), File::FNM_DOTMATCH))