diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index b1e9e3a79d..a13c5237af 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -434,8 +434,8 @@ assert_equal "allocator undefined for Thread", %q{ r = Ractor.new obj do |msg| msg end - rescue TypeError => e - e.message #=> no _dump_data is defined for class Thread + rescue Ractor::IsolationError => e + e.cause.message #=> no _dump_data is defined for class Thread else 'ng' end @@ -1429,7 +1429,7 @@ assert_equal "ok", %q{ end begin Ractor.new{} << err - rescue TypeError + rescue Ractor::IsolationError 'ok' end } diff --git a/ractor.c b/ractor.c index 096bda5df6..f66c25c486 100644 --- a/ractor.c +++ b/ractor.c @@ -1945,7 +1945,12 @@ copy_enter(VALUE obj, struct obj_traverse_replace_data *data) return traverse_skip; } else { - data->replacement = rb_obj_clone(obj); + int state; + VALUE result = rb_protect(rb_obj_clone, obj, &state); + if (state) { + rb_raise(rb_eRactorIsolationError, "cannot copy %"PRIsVALUE"", obj); + } + data->replacement = result; return traverse_cont; } } diff --git a/test/ruby/test_ractor.rb b/test/ruby/test_ractor.rb index 74de2bf9cd..7e4e51ac34 100644 --- a/test/ruby/test_ractor.rb +++ b/test/ruby/test_ractor.rb @@ -30,6 +30,10 @@ class TestRactor < Test::Unit::TestCase assert_make_shareable(x) end + def test_cannot_copy_proc + assert_unshareable(-> { }, /cannot copy/, copy: true) + end + def test_shareability_of_method_proc str = +"" @@ -207,10 +211,10 @@ class TestRactor < Test::Unit::TestCase assert Ractor.shareable?(obj), "object didn't become shareable" end - def assert_unshareable(obj, msg=nil, exception: Ractor::IsolationError) + def assert_unshareable(obj, msg=nil, copy: false, exception: Ractor::IsolationError) refute Ractor.shareable?(obj), "object is already shareable" assert_raise_with_message(exception, msg) do - Ractor.make_shareable(obj) + Ractor.make_shareable(obj, copy:) end refute Ractor.shareable?(obj), "despite raising, object became shareable" end