aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-09-25 18:31:04 +0900
committerKoichi Sasada <ko1@atdot.net>2020-09-25 20:37:38 +0900
commitcaaa36b4e6d0d59f0aa21049c063b140aa5aae4f (patch)
tree51e95c8e7be7a1a1793ab02a4c9f3a2cf2e1867f
parent890bc2cdde4097390f3b71dfeaa36dd92ee0afe2 (diff)
downloadruby-caaa36b4e6d0d59f0aa21049c063b140aa5aae4f.tar.gz
prohibi method call by defined_method in other racotrs
We can not call a non-isolated Proc in multiple ractors.
-rw-r--r--bootstraptest/test_ractor.rb11
-rw-r--r--method.h1
-rw-r--r--vm_insnhelper.c7
-rw-r--r--vm_method.c2
4 files changed, 20 insertions, 1 deletions
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index ff99521a76..a71f00672b 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -724,6 +724,17 @@ assert_equal 'can not set constants with non-shareable objects by non-main Racto
end
}
+# define_method is not allowed
+assert_equal "defined in a different Ractor", %q{
+ str = "foo"
+ define_method(:buggy){|i| str << "#{i}"}
+ begin
+ Ractor.new{buggy(10)}.take
+ rescue => e
+ e.cause.message
+ end
+}
+
# Immutable Array and Hash are shareable, so it can be shared with constants
assert_equal '[1000, 3]', %q{
A = Array.new(1000).freeze # [nil, ...]
diff --git a/method.h b/method.h
index dae0a4f43f..5b6fe2d800 100644
--- a/method.h
+++ b/method.h
@@ -159,6 +159,7 @@ typedef struct rb_method_refined_struct {
typedef struct rb_method_bmethod_struct {
VALUE proc; /* should be marked */
struct rb_hook_list_struct *hooks;
+ VALUE defined_ractor;
} rb_method_bmethod_t;
enum method_optimized_type {
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 30177b7a19..3d2667dfa7 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2667,9 +2667,14 @@ vm_call_bmethod_body(rb_execution_context_t *ec, struct rb_calling_info *calling
rb_proc_t *proc;
VALUE val;
const struct rb_callcache *cc = cd->cc;
+ const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
+
+ if (cme->def->body.bmethod.defined_ractor != rb_ec_ractor_ptr(ec)->self) {
+ rb_raise(rb_eRuntimeError, "defined in a different Ractor");
+ }
/* control block frame */
- GetProcPtr(vm_cc_cme(cc)->def->body.bmethod.proc, proc);
+ GetProcPtr(cme->def->body.bmethod.proc, proc);
val = rb_vm_invoke_bmethod(ec, proc, calling->recv, calling->argc, argv, calling->kw_splat, calling->block_handler, vm_cc_cme(cc));
return val;
diff --git a/vm_method.c b/vm_method.c
index 0428ae6380..de48dc65a2 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -430,6 +430,7 @@ rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *de
}
case VM_METHOD_TYPE_BMETHOD:
RB_OBJ_WRITE(me, &def->body.bmethod.proc, (VALUE)opts);
+ RB_OBJ_WRITE(me, &def->body.bmethod.defined_ractor, GET_THREAD()->ractor->self);
return;
case VM_METHOD_TYPE_NOTIMPLEMENTED:
setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), rb_f_notimplement, -1);
@@ -471,6 +472,7 @@ method_definition_reset(const rb_method_entry_t *me)
break;
case VM_METHOD_TYPE_BMETHOD:
RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.proc);
+ RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.defined_ractor);
/* give up to check all in a list */
if (def->body.bmethod.hooks) rb_gc_writebarrier_remember((VALUE)me);
break;