Skip to content

Commit

Permalink
Ractor.make_shareable checks proc's sefl
Browse files Browse the repository at this point in the history
`Ractor.make_shareable(proc_obj)` raises an `IsolationError`
if the self of `proc_obj` is not a shareable object.

[Bug #18243]
  • Loading branch information
ko1 committed Dec 9, 2021
1 parent c5f68a9 commit cce3312
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 16 deletions.
32 changes: 20 additions & 12 deletions bootstraptest/test_ractor.rb
Expand Up @@ -190,21 +190,23 @@
# 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
}

# 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
}
Expand Down Expand Up @@ -1276,9 +1278,13 @@ def /(other)
# 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)
Expand Down Expand Up @@ -1326,10 +1332,12 @@ class C
# 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
Expand Down
12 changes: 8 additions & 4 deletions test/ruby/test_iseq.rb
Expand Up @@ -129,7 +129,7 @@ def (Object.new).touch(**) # :nodoc:
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
Expand All @@ -148,16 +148,20 @@ def (Object.new).touch(&) # :nodoc:

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
Expand Down
4 changes: 4 additions & 0 deletions vm.c
Expand Up @@ -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) {
Expand Down

0 comments on commit cce3312

Please sign in to comment.