Skip to content

Commit

Permalink
Eagerly defrost chilled strings
Browse files Browse the repository at this point in the history
[Bug #20390]

Co-authored-by: Jean Boussier <[email protected]>
  • Loading branch information
etiennebarrie and byroot committed Mar 26, 2024
1 parent 779f713 commit f4f5f70
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 1 deletion.
16 changes: 15 additions & 1 deletion ext/stringio/stringio.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ static long strio_write(VALUE self, VALUE str);
#define IS_STRIO(obj) (rb_typeddata_is_kind_of((obj), &strio_data_type))
#define error_inval(msg) (rb_syserr_fail(EINVAL, msg))
#define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : !NIL_P((ptr)->string) ? rb_enc_get((ptr)->string) : NULL)
#ifndef HAVE_RB_STR_CHILLED_P
static int
rb_str_chilled_p(VALUE str)
{
return 0;
}
#endif

static struct StringIO *
strio_alloc(void)
Expand Down Expand Up @@ -287,13 +294,17 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
else if (!argc) {
string = rb_enc_str_new("", 0, rb_default_external_encoding());
}
if (!NIL_P(string) && OBJ_FROZEN_RAW(string)) {

if (!NIL_P(string) && OBJ_FROZEN_RAW(string) && !rb_str_chilled_p(string)) {
if (ptr->flags & FMODE_WRITABLE) {
rb_syserr_fail(EACCES, 0);
}
}
else {
if (NIL_P(vmode)) {
if (!NIL_P(string) && rb_str_chilled_p(string)) {
rb_str_modify(string);
}
ptr->flags |= FMODE_WRITABLE;
}
}
Expand Down Expand Up @@ -481,6 +492,9 @@ strio_set_string(VALUE self, VALUE string)
rb_io_taint_check(self);
ptr->flags &= ~FMODE_READWRITE;
StringValue(string);
if (rb_str_chilled_p(string)) {
rb_str_modify(string);
}
ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
ptr->pos = 0;
ptr->lineno = 0;
Expand Down
33 changes: 33 additions & 0 deletions test/stringio/test_stringio.rb
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,39 @@ def test_coderange_after_overwrite
assert_predicate(s.string, :ascii_only?)
end

if eval(%{ "test".frozen? && !"test".equal?("test") }) # Ruby 3.4+ chilled strings
def test_chilled_string
silence_deprecation_warnings do
chilled_string = eval(%{""})
io = StringIO.new(chilled_string)
io << "test"
assert_equal("test", io.string)
assert_same(chilled_string, io.string)
end
end

def test_chilled_string_string_set
silence_deprecation_warnings do
io = StringIO.new
chilled_string = eval(%{""})
io.string = chilled_string
io << "test"
assert_equal("test", io.string)
assert_same(chilled_string, io.string)
end
end
end

private

def silence_deprecation_warnings
deprecated_was = Warning[:deprecated]
Warning[:deprecated] = false
yield
ensure
Warning[:deprecated] = deprecated_was
end

def assert_string(content, encoding, str, mesg = nil)
assert_equal([content, encoding], [str, str.encoding], mesg)
end
Expand Down

0 comments on commit f4f5f70

Please sign in to comment.