Skip to content

Commit a175c4c

Browse files
etiennebarriebyroot
andcommitted
Eagerly defrost chilled strings
[Bug #20390] Co-authored-by: Jean Boussier <[email protected]>
1 parent 779f713 commit a175c4c

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

ext/stringio/stringio.c

+15-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ static long strio_write(VALUE self, VALUE str);
4949
#define IS_STRIO(obj) (rb_typeddata_is_kind_of((obj), &strio_data_type))
5050
#define error_inval(msg) (rb_syserr_fail(EINVAL, msg))
5151
#define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : !NIL_P((ptr)->string) ? rb_enc_get((ptr)->string) : NULL)
52+
#ifndef HAVE_RB_STR_CHILLED_P
53+
static int
54+
rb_str_chilled_p(VALUE str)
55+
{
56+
return 0;
57+
}
58+
#endif
5259

5360
static struct StringIO *
5461
strio_alloc(void)
@@ -287,13 +294,17 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
287294
else if (!argc) {
288295
string = rb_enc_str_new("", 0, rb_default_external_encoding());
289296
}
290-
if (!NIL_P(string) && OBJ_FROZEN_RAW(string)) {
297+
298+
if (!NIL_P(string) && OBJ_FROZEN_RAW(string) && !rb_str_chilled_p(string)) {
291299
if (ptr->flags & FMODE_WRITABLE) {
292300
rb_syserr_fail(EACCES, 0);
293301
}
294302
}
295303
else {
296304
if (NIL_P(vmode)) {
305+
if (!NIL_P(string) && rb_str_chilled_p(string)) {
306+
rb_str_modify(string);
307+
}
297308
ptr->flags |= FMODE_WRITABLE;
298309
}
299310
}
@@ -481,6 +492,9 @@ strio_set_string(VALUE self, VALUE string)
481492
rb_io_taint_check(self);
482493
ptr->flags &= ~FMODE_READWRITE;
483494
StringValue(string);
495+
if (rb_str_chilled_p(string)) {
496+
rb_str_modify(string);
497+
}
484498
ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
485499
ptr->pos = 0;
486500
ptr->lineno = 0;

test/stringio/test_stringio.rb

+21
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,27 @@ def test_coderange_after_overwrite
978978
assert_predicate(s.string, :ascii_only?)
979979
end
980980

981+
if eval(%{ "test".frozen? && !"test".equal?("test") }) # Ruby 3.4+ chilled strings
982+
def test_chilled_string
983+
chilled_string = eval(%{""})
984+
io = assert_warning(/literal string will be frozen/) { StringIO.new(chilled_string) }
985+
io << "test"
986+
assert_equal("test", io.string)
987+
assert_same(chilled_string, io.string)
988+
end
989+
990+
def test_chilled_string_string_set
991+
io = StringIO.new
992+
chilled_string = eval(%{""})
993+
assert_warning(/literal string will be frozen/) { io.string = chilled_string }
994+
io << "test"
995+
assert_equal("test", io.string)
996+
assert_same(chilled_string, io.string)
997+
end
998+
end
999+
1000+
private
1001+
9811002
def assert_string(content, encoding, str, mesg = nil)
9821003
assert_equal([content, encoding], [str, str.encoding], mesg)
9831004
end

0 commit comments

Comments
 (0)