From cce331272b07636d536c8227288ab3fbcf24e2aa Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Thu, 9 Dec 2021 03:58:44 +0900 Subject: `Ractor.make_shareable` checks proc's sefl `Ractor.make_shareable(proc_obj)` raises an `IsolationError` if the self of `proc_obj` is not a shareable object. [Bug #18243] --- bootstraptest/test_ractor.rb | 32 ++++++++++++++++++++------------ test/ruby/test_iseq.rb | 12 ++++++++---- vm.c | 4 ++++ 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index ef1e6afcac..e259684974 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -190,7 +190,7 @@ assert_equal '[:ok, :ok, :ok]', %q{ # Ractor.make_shareable issue for locals in proc [Bug #18023] assert_equal '[:a, :b, :c, :d, :e]', %q{ v1, v2, v3, v4, v5 = :a, :b, :c, :d, :e - closure = Proc.new { [v1, v2, v3, v4, v5] } + closure = Ractor.current.instance_eval{ Proc.new { [v1, v2, v3, v4, v5] } } Ractor.make_shareable(closure).call } @@ -198,13 +198,15 @@ assert_equal '[:a, :b, :c, :d, :e]', %q{ # Ractor.make_shareable issue for locals in proc [Bug #18023] assert_equal '[:a, :b, :c, :d, :e, :f, :g]', %q{ a = :a - closure = -> { - b, c, d = :b, :c, :d + closure = Ractor.current.instance_eval do -> { - e, f, g = :e, :f, :g - -> { [a, b, c, d, e, f, g] } + b, c, d = :b, :c, :d + -> { + e, f, g = :e, :f, :g + -> { [a, b, c, d, e, f, g] } + }.call }.call - }.call + end Ractor.make_shareable(closure).call } @@ -1276,9 +1278,13 @@ assert_equal 'true', %q{ # Ractor.make_shareable(a_proc) makes a proc shareable. assert_equal 'true', %q{ a = [1, [2, 3], {a: "4"}] - pr = Proc.new do - a + + pr = Ractor.current.instance_eval do + Proc.new do + a + end end + Ractor.make_shareable(a) # referred value should be shareable Ractor.make_shareable(pr) Ractor.shareable?(pr) @@ -1326,10 +1332,12 @@ assert_equal '1', %q{ # Ractor.make_shareable(a_proc) makes a proc shareable. assert_equal 'can not make a Proc shareable because it accesses outer variables (a).', %q{ a = b = nil - pr = Proc.new do - c = b # assign to a is okay because c is block local variable - # reading b is okay - a = b # assign to a is not allowed #=> Ractor::Error + pr = Ractor.current.instance_eval do + Proc.new do + c = b # assign to a is okay because c is block local variable + # reading b is okay + a = b # assign to a is not allowed #=> Ractor::Error + end end begin diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index ac191531de..aa0bf35b80 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -129,7 +129,7 @@ class TestISeq < Test::Unit::TestCase def test_lambda_with_ractor_roundtrip iseq = compile(<<~EOF, __LINE__+1) x = 42 - y = lambda { x } + y = nil.instance_eval{ lambda { x } } Ractor.make_shareable(y) y.call EOF @@ -148,16 +148,20 @@ class TestISeq < Test::Unit::TestCase def test_ractor_unshareable_outer_variable name = "\u{2603 26a1}" - y = eval("proc {#{name} = nil; proc {|x| #{name} = x}}").call + y = nil.instance_eval do + eval("proc {#{name} = nil; proc {|x| #{name} = x}}").call + end assert_raise_with_message(ArgumentError, /\(#{name}\)/) do Ractor.make_shareable(y) end - y = eval("proc {#{name} = []; proc {|x| #{name}}}").call + y = nil.instance_eval do + eval("proc {#{name} = []; proc {|x| #{name}}}").call + end assert_raise_with_message(Ractor::IsolationError, /`#{name}'/) do Ractor.make_shareable(y) end obj = Object.new - def obj.foo(*) ->{super} end + def obj.foo(*) nil.instance_eval{ ->{super} } end assert_raise_with_message(Ractor::IsolationError, /hidden variable/) do Ractor.make_shareable(obj.foo) end diff --git a/vm.c b/vm.c index ad687d579a..73d6cd9d5d 100644 --- a/vm.c +++ b/vm.c @@ -1181,6 +1181,10 @@ rb_proc_ractor_make_shareable(VALUE self) rb_proc_t *proc = (rb_proc_t *)RTYPEDDATA_DATA(self); if (proc->block.type != block_type_iseq) rb_raise(rb_eRuntimeError, "not supported yet"); + if (!rb_ractor_shareable_p(vm_block_self(&proc->block))) { + rb_raise(rb_eRactorIsolationError, "Proc's self is not shareable"); + } + VALUE read_only_variables = Qfalse; if (iseq->body->outer_variables) { -- cgit v1.2.3