From 3e605a781970cef365002167634a1b5a176bffcb Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 25 Oct 2022 12:15:03 +0900 Subject: [PATCH] [ruby/tmpdir] [Bug #18933] Make `Dir.mktmpdir` Ractor-safe Fix https://bugs.ruby-lang.org/issues/18933 https://github.com/ruby/tmpdir/commit/446e636434 --- lib/tmpdir.rb | 16 +++++++++++----- test/test_tmpdir.rb | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/lib/tmpdir.rb b/lib/tmpdir.rb index 55920a4a743ebc..db5ed978cd3bb7 100644 --- a/lib/tmpdir.rb +++ b/lib/tmpdir.rb @@ -13,15 +13,20 @@ class Dir - @@systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp' + # Class variables are inaccessible from non-main Ractor. + # And instance variables too, in Ruby 3.0. + + # System-wide temporary directory path + SYSTMPDIR = (defined?(Etc.systmpdir) ? Etc.systmpdir.freeze : '/tmp') + private_constant :SYSTMPDIR ## # Returns the operating system's temporary file path. def self.tmpdir - ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', @@systmpdir], ['/tmp']*2, ['.']*2].find do |name, dir| + ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', SYSTMPDIR], ['/tmp']*2, ['.']*2].find do |name, dir| unless dir - next if !(dir = ENV[name]) or dir.empty? + next if !(dir = ENV[name] rescue next) or dir.empty? end dir = File.expand_path(dir) stat = File.stat(dir) rescue next @@ -118,16 +123,17 @@ def tmpdir UNUSABLE_CHARS = "^,-.0-9A-Z_a-z~" # Dedicated random number generator - RANDOM = Random.new + RANDOM = Object.new class << RANDOM # :nodoc: # Maximum random number MAX = 36**6 # < 0x100000000 # Returns new random string upto 6 bytes def next - rand(MAX).to_s(36) + (::Random.urandom(4).unpack1("L")%MAX).to_s(36) end end + RANDOM.freeze private_constant :RANDOM # Generates and yields random names to create a temporary name diff --git a/test/test_tmpdir.rb b/test/test_tmpdir.rb index eada416f6fceb5..054ca15d7a7634 100644 --- a/test/test_tmpdir.rb +++ b/test/test_tmpdir.rb @@ -115,4 +115,20 @@ def assert_mktmpdir_traversal end end end + + def test_ractor + assert_ractor(<<~'end;', require: "tmpdir") + r = Ractor.new do + Dir.mktmpdir() do |d| + Ractor.yield d + Ractor.receive + end + end + dir = r.take + assert_file.directory? dir + r.send true + r.take + assert_file.not_exist? dir + end; + end end