Skip to content

Commit 1d3fe2c

Browse files
jhawthornluke-gru
andcommitted
Change bmethod defined_ractor to use id instead
When defining a bmethod, we recorded the current Ractor's object in the method. However that was never marked and so could be GC'd and reused by a future Ractor. Instead we can use the Ractor's id, which we expect to be unique forever. Co-authored-by: Luke Gruber <luke.gru@gmail.com>
1 parent de2c2bd commit 1d3fe2c

4 files changed

Lines changed: 29 additions & 5 deletions

File tree

bootstraptest/test_ractor.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,3 +2413,28 @@ def call_test(obj)
24132413
:ok
24142414
end
24152415
RUBY
2416+
2417+
# When creating bmethods in Ractors, they should only be usable from their
2418+
# defining ractor, even if it is GC'd
2419+
assert_equal 'ok', <<~'RUBY'
2420+
CLASSES = 1000.times.map do
2421+
Ractor.new do
2422+
Class.new do
2423+
define_method(:foo) {}
2424+
end
2425+
end
2426+
end.map(&:value).freeze
2427+
2428+
any = 1000.times.map do
2429+
Ractor.new do
2430+
CLASSES.any? do |klass|
2431+
begin
2432+
klass.new.foo
2433+
true
2434+
rescue RuntimeError
2435+
false
2436+
end
2437+
end
2438+
end
2439+
end.map(&:value).none? && :ok
2440+
RUBY

method.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ typedef struct rb_method_refined_struct {
167167
typedef struct rb_method_bmethod_struct {
168168
VALUE proc; /* should be marked */
169169
struct rb_hook_list_struct *hooks;
170-
VALUE defined_ractor;
170+
rb_serial_t defined_ractor_id;
171171
} rb_method_bmethod_t;
172172

173173
enum method_optimized_type {

vm_insnhelper.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4121,7 +4121,7 @@ vm_call_bmethod_body(rb_execution_context_t *ec, struct rb_calling_info *calling
41214121
VALUE procv = cme->def->body.bmethod.proc;
41224122

41234123
if (!RB_OBJ_SHAREABLE_P(procv) &&
4124-
cme->def->body.bmethod.defined_ractor != rb_ractor_self(rb_ec_ractor_ptr(ec))) {
4124+
cme->def->body.bmethod.defined_ractor_id != rb_ractor_id(rb_ec_ractor_ptr(ec))) {
41254125
rb_raise(rb_eRuntimeError, "defined with an un-shareable Proc in a different Ractor");
41264126
}
41274127

@@ -4144,7 +4144,7 @@ vm_call_iseq_bmethod(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct
41444144
VALUE procv = cme->def->body.bmethod.proc;
41454145

41464146
if (!RB_OBJ_SHAREABLE_P(procv) &&
4147-
cme->def->body.bmethod.defined_ractor != rb_ractor_self(rb_ec_ractor_ptr(ec))) {
4147+
cme->def->body.bmethod.defined_ractor_id != rb_ractor_id(rb_ec_ractor_ptr(ec))) {
41484148
rb_raise(rb_eRuntimeError, "defined with an un-shareable Proc in a different Ractor");
41494149
}
41504150

vm_method.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,7 @@ rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *de
10201020
}
10211021
case VM_METHOD_TYPE_BMETHOD:
10221022
RB_OBJ_WRITE(me, &def->body.bmethod.proc, (VALUE)opts);
1023-
RB_OBJ_WRITE(me, &def->body.bmethod.defined_ractor, rb_ractor_self(GET_RACTOR()));
1023+
def->body.bmethod.defined_ractor_id = rb_ractor_id(rb_ec_ractor_ptr(GET_EC()));
10241024
return;
10251025
case VM_METHOD_TYPE_NOTIMPLEMENTED:
10261026
setup_method_cfunc_struct(UNALIGNED_MEMBER_PTR(def, body.cfunc), (VALUE(*)(ANYARGS))rb_f_notimplement_internal, -1);
@@ -1060,7 +1060,6 @@ method_definition_reset(const rb_method_entry_t *me)
10601060
break;
10611061
case VM_METHOD_TYPE_BMETHOD:
10621062
RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.proc);
1063-
RB_OBJ_WRITTEN(me, Qundef, def->body.bmethod.defined_ractor);
10641063
/* give up to check all in a list */
10651064
if (def->body.bmethod.hooks) rb_gc_writebarrier_remember((VALUE)me);
10661065
break;

0 commit comments

Comments
 (0)