diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index 1c89cd40ee7e8b..ded11ccf69004a 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -408,8 +408,8 @@ def test n 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 @@ -1403,7 +1403,7 @@ class C end begin Ractor.new{} << err - rescue TypeError + rescue Ractor::IsolationError 'ok' end } diff --git a/ractor.c b/ractor.c index 317b24dca24694..620cb02c1ca81f 100644 --- a/ractor.c +++ b/ractor.c @@ -1925,7 +1925,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 97af7e7413f44e..eb8f122548a917 100644 --- a/test/ruby/test_ractor.rb +++ b/test/ruby/test_ractor.rb @@ -30,6 +30,10 @@ def test_shareability_of_curried_proc assert_make_shareable(x) end + def test_cannot_copy_proc + assert_unshareable(-> { }, /cannot copy/, copy: true) + end + def test_shareability_of_method_proc str = +"" @@ -150,10 +154,10 @@ def assert_make_shareable(obj) 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