diff --git a/string.c b/string.c index 280768cedb4..f9a86f71e1b 100644 --- a/string.c +++ b/string.c @@ -2194,7 +2194,10 @@ rb_str_init(int argc, VALUE *argv, VALUE str) TERM_FILL(&RSTRING(str)->as.heap.ptr[len], termlen); if (n == 1) { memcpy(RSTRING(str)->as.heap.ptr, RSTRING_PTR(orig), len); - rb_enc_cr_str_exact_copy(str, orig); + if (!enc || rb_enc_get(orig) == enc) { + rb_enc_cr_str_exact_copy(str, orig); + enc = 0; + } } FL_SET(str, STR_NOEMBED); RSTRING(str)->as.heap.aux.capa = capa; @@ -2203,7 +2206,8 @@ rb_str_init(int argc, VALUE *argv, VALUE str) rb_str_replace(str, orig); } if (enc) { - rb_enc_associate(str, enc); + str_modifiable(str); + rb_enc_raw_set(str, enc); ENC_CODERANGE_CLEAR(str); } } diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index e4d00d56159..0ea21a9ccf7 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -1,5 +1,6 @@ # frozen_string_literal: false require 'test/unit' +require '-test-/string' class TestString < Test::Unit::TestCase WIDE_ENCODINGS = [ @@ -4649,4 +4650,38 @@ class TestString2 < TestString super @cls = S2 end + + def assert_capacity(capa, str, msg) + assert_equal capa, Bug::String.capacity(str), msg + end + + def test_capacity_inflation + orig = ("\u{30AF}" * 5) + all_assertions_foreach(nil, Encoding::UTF_8, *WIDE_ENCODINGS) do |enc| + assert_capacity(200, S2.new(orig.encode(enc), encoding: "UTF-8", capacity: 200), enc.name) + end + end + + def test_capacity_no_inflation + orig = "hello" + all_assertions_foreach(nil, Encoding::UTF_8, *WIDE_ENCODINGS) do |enc| + assert_capacity(100, S2.new(orig, encoding: enc, capacity: 100), enc.name) + end + end + + def test_capacity_no_overflow_on_append + orig = ("\u{30AF}" * 5) + all_assertions_foreach(nil, *WIDE_ENCODINGS) do |enc| + encoded = orig.encode(enc) + size = encoded.bytesize + + s = S2.new(encoded, encoding: "UTF-8", capacity: 200) + s << "x" * 191 + assert_equal(size + 191, s.bytesize, enc.name) + + s = S2.new(encoded, encoding: "UTF-8", capacity: 207) + s << "y" * 207 + assert_equal(size + 207, s.bytesize, enc.name) + end + end end