Skip to content

Commit f4f5f70

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

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-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

+33
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,39 @@ 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+
silence_deprecation_warnings do
984+
chilled_string = eval(%{""})
985+
io = StringIO.new(chilled_string)
986+
io << "test"
987+
assert_equal("test", io.string)
988+
assert_same(chilled_string, io.string)
989+
end
990+
end
991+
992+
def test_chilled_string_string_set
993+
silence_deprecation_warnings do
994+
io = StringIO.new
995+
chilled_string = eval(%{""})
996+
io.string = chilled_string
997+
io << "test"
998+
assert_equal("test", io.string)
999+
assert_same(chilled_string, io.string)
1000+
end
1001+
end
1002+
end
1003+
1004+
private
1005+
1006+
def silence_deprecation_warnings
1007+
deprecated_was = Warning[:deprecated]
1008+
Warning[:deprecated] = false
1009+
yield
1010+
ensure
1011+
Warning[:deprecated] = deprecated_was
1012+
end
1013+
9811014
def assert_string(content, encoding, str, mesg = nil)
9821015
assert_equal([content, encoding], [str, str.encoding], mesg)
9831016
end

0 commit comments

Comments
 (0)