[Bug #22461] Fix dangling pointers after associating encoding

`rb_enc_associate` may re-allocate the string buffer because of the
terminator length change.
This commit is contained in:
Nobuyoshi Nakada committed 2026-10-22 10:46:22 +09:00
1 parent f4c7ad48ce
commit faefcb1105
2 files changed
+28 -5
Notes: git 2026-10-22 02:58:06 +00:00

No files matched your search

+16 -5
View File
@@ -234,6 +234,18 @@ rb_f_sprintf(int argc, const VALUE *argv)
return rb_str_format(argc - 1, argv + 1, GETNTHARG(0));
}
static char *
reassoc_enc(VALUE result, rb_encoding *enc)
{
return RSTRING_PTR(rb_enc_associate(result, enc));
}
static char *
reassoc_enc_index(VALUE result, int encidx)
{
return RSTRING_PTR(rb_enc_associate_index(result, encidx));
}
VALUE
rb_str_format_ary(int argc, const VALUE *argv, VALUE fmt, VALUE ary)
{
@@ -295,8 +307,7 @@ rb_str_format_ary(int argc, const VALUE *argv, VALUE fmt, VALUE ary)
blen = 0;
bsiz = 120;
result = rb_str_buf_new(bsiz);
rb_enc_associate(result, enc);
buf = RSTRING_PTR(result);
buf = reassoc_enc(result, enc);
memset(buf, 0, bsiz);
ENC_CODERANGE_SET(result, coderange);
@@ -487,7 +498,7 @@ rb_str_format_ary(int argc, const VALUE *argv, VALUE fmt, VALUE ary)
}
if (encidx >= 0 && encidx != rb_enc_to_index(enc)) {
/* special case */
rb_enc_associate_index(result, encidx);
buf = reassoc_enc_index(result, encidx);
enc = rb_enc_from_index(encidx);
coderange = ENC_CODERANGE_VALID;
}
@@ -550,13 +561,13 @@ rb_str_format_ary(int argc, const VALUE *argv, VALUE fmt, VALUE ary)
if (flags&FMINUS) {
FILL_(' ', width);
}
rb_enc_associate(result, enc);
buf = reassoc_enc(result, enc);
break;
}
}
PUSH(RSTRING_PTR(str), len);
RB_GC_GUARD(str);
rb_enc_associate(result, enc);
buf = reassoc_enc(result, enc);
}
break;
+12
View File
@@ -574,4 +574,16 @@ class TestSprintf < Test::Unit::TestCase
assert_equal i, str.bytesize
end
end
def test_dangling_pointer_after_encoding_set
str = "\u0141" * 61
wide_encodings = [
Encoding::UTF_16BE, Encoding::UTF_16LE,
Encoding::UTF_32BE, Encoding::UTF_32LE,
]
all_assertions_foreach(nil, *wide_encodings) do |enc|
s = str.encode(enc)
assert_equal(s, ("%s" % s), enc.name)
end
end
end