Skip to content

Commit 975d429

Browse files
Unify class ivar isolation diagnostics
Include ivar and class names in JIT read errors, avoid invoking custom to_s while formatting isolation errors, and cover creator ownership across Ractors. Validation: make -j8 check (passed).
1 parent da6300d commit 975d429

2 files changed

Lines changed: 75 additions & 4 deletions

File tree

‎bootstraptest/test_ractor.rb‎

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,72 @@ class C
907907
end
908908
RUBY
909909

910+
# a non-main Ractor can read, set, and remove ivars of classes/modules it created
911+
assert_equal 'ok', <<~'RUBY', frozen_string_literal: false
912+
Ractor.new do
913+
[Class.new, Module.new].each do |mod|
914+
mod.instance_variable_set(:@iv, 'str')
915+
raise unless mod.instance_variable_get(:@iv) == 'str'
916+
raise unless mod.remove_instance_variable(:@iv) == 'str'
917+
end
918+
:ok
919+
end.value
920+
RUBY
921+
922+
# even main cannot modify another Ractor's module; reporting its name must not call to_s
923+
assert_equal 'true', <<~'RUBY', frozen_string_literal: false
924+
port = Ractor::Port.new
925+
r = Ractor.new(port) do |port|
926+
mod = Module.new
927+
mod.set_temporary_name('worker_module')
928+
mod.instance_variable_set(:@iv, 'str')
929+
def mod.to_s = raise('to_s must not be called')
930+
port << mod
931+
Ractor.receive
932+
end
933+
mod = port.receive
934+
935+
begin
936+
messages = [[:instance_variable_set, :@iv, 'other'], [:remove_instance_variable, :@iv]].map do |args|
937+
begin
938+
mod.public_send(*args)
939+
rescue Ractor::IsolationError => e
940+
e.message
941+
end
942+
end
943+
messages == ["can not set instance variables of classes/modules created by another Ractor (@iv from worker_module)"] * 2
944+
ensure
945+
r << nil
946+
r.join
947+
end
948+
RUBY
949+
950+
# normal and JIT-compiled ivar reads report the same names without calling to_s
951+
assert_equal 'true', <<~'RUBY', frozen_string_literal: false
952+
class C
953+
@iv = 'str'
954+
def self.read = @iv
955+
def self.to_s = raise('to_s must not be called')
956+
end
957+
958+
Ractor.new do
959+
messages = []
960+
begin
961+
C.instance_variable_get(:@iv)
962+
rescue Ractor::IsolationError => e
963+
messages << e.message
964+
end
965+
40.times do
966+
begin
967+
C.read
968+
rescue Ractor::IsolationError => e
969+
messages << e.message
970+
end
971+
end
972+
messages == ["can not get unshareable values from instance variables of classes/modules created by another Ractor (@iv from C)"] * 41
973+
end.value
974+
RUBY
975+
910976
# setting an ivar on a shareable but unfrozen object is not allowed, by instance_variable_set
911977
assert_equal "can't modify instance variables of a shareable Ractor", %q{
912978
shared = Ractor.new{}

‎variable.c‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,7 +1271,7 @@ class_ivar_set_ractor_check(VALUE klass, ID id)
12711271
"can not set instance variables of classes/modules "
12721272
"created by another Ractor (%"PRIsVALUE" from %"PRIsVALUE")",
12731273
rb_id2str(id),
1274-
klass
1274+
rb_class_path(klass)
12751275
);
12761276
}
12771277
}
@@ -1625,7 +1625,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
16251625
"can not get unshareable values from instance variables of classes/modules "
16261626
"created by another Ractor (%"PRIsVALUE" from %"PRIsVALUE")",
16271627
rb_id2str(id),
1628-
obj
1628+
rb_class_path(obj)
16291629
);
16301630
}
16311631
}
@@ -1657,8 +1657,13 @@ rb_ivar_get_at(VALUE obj, attr_index_t index, ID id)
16571657
VALUE val = rb_imemo_fields_ptr(fields_obj)[index];
16581658

16591659
if (UNLIKELY(!rb_class_owned_p(obj)) && !rb_ractor_shareable_p(val)) {
1660-
rb_raise(rb_eRactorIsolationError,
1661-
"can not get unshareable values from instance variables of classes/modules created by another Ractor");
1660+
rb_raise(
1661+
rb_eRactorIsolationError,
1662+
"can not get unshareable values from instance variables of classes/modules "
1663+
"created by another Ractor (%"PRIsVALUE" from %"PRIsVALUE")",
1664+
rb_id2str(id),
1665+
rb_class_path(obj)
1666+
);
16621667
}
16631668

16641669
return val;

0 commit comments

Comments
 (0)