Freeze $/ and make it ractor safe
[Feature #21109] By always freezing when setting the global rb_rs variable, we can ensure it is not modified and can be accessed from a ractor. We're also making sure it's an instance of String and does not have any instance variables. Of course, if $/ is changed at runtime, it may cause surprising behavior but doing so is deprecated already anyway. Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
This commit is contained in:
parent
49d49d5985
commit
6ecfe643b5
Notes:
git
2025-03-27 16:55:12 +00:00
@ -61,6 +61,7 @@ size_t rb_str_size_as_embedded(VALUE);
|
||||
bool rb_str_reembeddable_p(VALUE);
|
||||
VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE);
|
||||
VALUE rb_str_with_debug_created_info(VALUE, VALUE, int);
|
||||
VALUE rb_str_frozen_bare_string(VALUE);
|
||||
|
||||
/* error.c */
|
||||
void rb_warn_unchilled_literal(VALUE str);
|
||||
|
25
io.c
25
io.c
@ -8673,6 +8673,25 @@ deprecated_str_setter(VALUE val, ID id, VALUE *var)
|
||||
*var = val;
|
||||
}
|
||||
|
||||
static void
|
||||
deprecated_rs_setter(VALUE val, ID id, VALUE *var)
|
||||
{
|
||||
if (!NIL_P(val)) {
|
||||
if (!RB_TYPE_P(val, T_STRING)) {
|
||||
rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
|
||||
}
|
||||
if (rb_str_equal(val, rb_default_rs)) {
|
||||
val = rb_default_rs;
|
||||
}
|
||||
else {
|
||||
val = rb_str_frozen_bare_string(val);
|
||||
}
|
||||
rb_enc_str_coderange(val);
|
||||
rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
|
||||
}
|
||||
*var = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* print(*objects) -> nil
|
||||
@ -15713,8 +15732,10 @@ Init_IO(void)
|
||||
rb_vm_register_global_object(rb_default_rs);
|
||||
rb_rs = rb_default_rs;
|
||||
rb_output_rs = Qnil;
|
||||
rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
|
||||
rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter);
|
||||
rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
|
||||
rb_gvar_ractor_local("$/"); // not local but ractor safe
|
||||
rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
|
||||
rb_gvar_ractor_local("$-0"); // not local but ractor safe
|
||||
rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
|
||||
|
||||
rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
|
||||
|
4
ruby.c
4
ruby.c
@ -1325,11 +1325,11 @@ proc_0_option(ruby_cmdline_options_t *opt, const char *s)
|
||||
if (v > 0377)
|
||||
rb_rs = Qnil;
|
||||
else if (v == 0 && numlen >= 2) {
|
||||
rb_rs = rb_str_new2("");
|
||||
rb_rs = rb_fstring_lit("");
|
||||
}
|
||||
else {
|
||||
c = v & 0xff;
|
||||
rb_rs = rb_str_new(&c, 1);
|
||||
rb_rs = rb_str_freeze(rb_str_new(&c, 1));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
13
spec/ruby/command_line/dash_0_spec.rb
Executable file
13
spec/ruby/command_line/dash_0_spec.rb
Executable file
@ -0,0 +1,13 @@
|
||||
require_relative '../spec_helper'
|
||||
|
||||
describe "The -0 command line option" do
|
||||
it "sets $/ and $-0" do
|
||||
ruby_exe("puts $/, $-0", options: "-072").should == ":\n:\n"
|
||||
end
|
||||
|
||||
ruby_version_is "3.5" do
|
||||
it "sets $/ and $-0 as a frozen string" do
|
||||
ruby_exe("puts $/.frozen?, $-0.frozen?", options: "-072").should == "true\ntrue\n"
|
||||
end
|
||||
end
|
||||
end
|
@ -559,12 +559,39 @@ describe "Predefined global $/" do
|
||||
$VERBOSE = @verbose
|
||||
end
|
||||
|
||||
it "can be assigned a String" do
|
||||
str = "abc"
|
||||
$/ = str
|
||||
$/.should equal(str)
|
||||
ruby_version_is ""..."3.5" do
|
||||
it "can be assigned a String" do
|
||||
str = +"abc"
|
||||
$/ = str
|
||||
$/.should equal(str)
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "3.5" do
|
||||
it "makes a new frozen String from the assigned String" do
|
||||
string_subclass = Class.new(String)
|
||||
str = string_subclass.new("abc")
|
||||
str.instance_variable_set(:@ivar, 1)
|
||||
$/ = str
|
||||
$/.should.frozen?
|
||||
$/.should be_an_instance_of(String)
|
||||
$/.should_not.instance_variable_defined?(:@ivar)
|
||||
$/.should == str
|
||||
end
|
||||
|
||||
it "makes a new frozen String if it's not frozen" do
|
||||
str = +"abc"
|
||||
$/ = str
|
||||
$/.should.frozen?
|
||||
$/.should == str
|
||||
end
|
||||
|
||||
it "assigns the given String if it's frozen and has no instance variables" do
|
||||
str = "abc".freeze
|
||||
$/ = str
|
||||
$/.should equal(str)
|
||||
end
|
||||
end
|
||||
it "can be assigned nil" do
|
||||
$/ = nil
|
||||
$/.should be_nil
|
||||
@ -608,10 +635,38 @@ describe "Predefined global $-0" do
|
||||
$VERBOSE = @verbose
|
||||
end
|
||||
|
||||
it "can be assigned a String" do
|
||||
str = "abc"
|
||||
$-0 = str
|
||||
$-0.should equal(str)
|
||||
ruby_version_is ""..."3.5" do
|
||||
it "can be assigned a String" do
|
||||
str = +"abc"
|
||||
$-0 = str
|
||||
$-0.should equal(str)
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "3.5" do
|
||||
it "makes a new frozen String from the assigned String" do
|
||||
string_subclass = Class.new(String)
|
||||
str = string_subclass.new("abc")
|
||||
str.instance_variable_set(:@ivar, 1)
|
||||
$-0 = str
|
||||
$-0.should.frozen?
|
||||
$-0.should be_an_instance_of(String)
|
||||
$-0.should_not.instance_variable_defined?(:@ivar)
|
||||
$-0.should == str
|
||||
end
|
||||
|
||||
it "makes a new frozen String if it's not frozen" do
|
||||
str = +"abc"
|
||||
$-0 = str
|
||||
$-0.should.frozen?
|
||||
$-0.should == str
|
||||
end
|
||||
|
||||
it "assigns the given String if it's frozen and has no instance variables" do
|
||||
str = "abc".freeze
|
||||
$-0 = str
|
||||
$-0.should equal(str)
|
||||
end
|
||||
end
|
||||
|
||||
it "can be assigned nil" do
|
||||
|
8
string.c
8
string.c
@ -1480,6 +1480,14 @@ rb_str_new_frozen_String(VALUE orig)
|
||||
return str_new_frozen(rb_cString, orig);
|
||||
}
|
||||
|
||||
|
||||
VALUE
|
||||
rb_str_frozen_bare_string(VALUE orig)
|
||||
{
|
||||
if (RB_LIKELY(BARE_STRING_P(orig) && OBJ_FROZEN_RAW(orig))) return orig;
|
||||
return str_new_frozen(rb_cString, orig);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_str_tmp_frozen_acquire(VALUE orig)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user