From 37bd795cf8bc9681fccaf9b2d42292b14610a310 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 17 Dec 2021 14:22:14 +0900 Subject: [PATCH] `ENV` ivars should not be accessible from ractors The `ENV` object can have instance variables like other objects, but they should be accessed only on the main ractor. fix https://github.com/ruby/ruby/pull/5263#issuecomment-995585766 --- hash.c | 13 ++++++++++++- test/ruby/test_env.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/hash.c b/hash.c index deb5e77872f774..da9af425c1432c 100644 --- a/hash.c +++ b/hash.c @@ -6653,6 +6653,17 @@ env_dup(VALUE obj) rb_raise(rb_eTypeError, "Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash"); } +const rb_data_type_t env_data_type = { + "ENV", + { + NULL, + RUBY_DEFAULT_FREE, + NULL, + NULL, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED, +}; + /* * A \Hash maps each of its unique keys to a specific value. * @@ -7308,7 +7319,7 @@ Init_Hash(void) * envtbl = rb_define_class("ENV", rb_cObject); */ origenviron = environ; - envtbl = rb_obj_alloc(rb_cObject); + envtbl = TypedData_Wrap_Struct(rb_cObject, &env_data_type, NULL); rb_extend_object(envtbl, rb_mEnumerable); FL_SET_RAW(envtbl, RUBY_FL_SHAREABLE); diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb index 442fc60f7eeaef..87ccd5102b72d5 100644 --- a/test/ruby/test_env.rb +++ b/test/ruby/test_env.rb @@ -1434,6 +1434,36 @@ def test_shared_substring_in_ractor end; end + def test_ivar_in_env_should_not_be_access_from_non_main_ractors + assert_ractor <<~RUBY + ENV.instance_eval{ @a = "hello" } + assert_equal "hello", ENV.instance_variable_get(:@a) + + r_get = Ractor.new do + ENV.instance_variable_get(:@a) + rescue Ractor::IsolationError => e + e + end + assert_equal Ractor::IsolationError, r_get.take.class + + r_get = Ractor.new do + ENV.instance_eval{ @a } + rescue Ractor::IsolationError => e + e + end + + assert_equal Ractor::IsolationError, r_get.take.class + + r_set = Ractor.new do + ENV.instance_eval{ @b = "hello" } + rescue Ractor::IsolationError => e + e + end + + assert_equal Ractor::IsolationError, r_set.take.class + RUBY + end + if RUBY_PLATFORM =~ /bccwin|mswin|mingw/ def test_memory_leak_aset bug9977 = '[ruby-dev:48323] [Bug #9977]'