aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2020-07-18 23:52:27 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2020-07-20 14:59:19 +0900
commit6ff9604f85bf5ffcb6dbfd9ff99ab420c9a5f415 (patch)
treef78d51354355cdf1bfe683e8451fc2bc1864645c
parent840115bf46476dc2b3c175f7716b4d6000906f40 (diff)
downloadruby-6ff9604f85bf5ffcb6dbfd9ff99ab420c9a5f415.tar.gz
[ruby/stringio] Raise an error if encoding conversion not succeeded
As `rb_str_conv_enc()` returns the argument string object itself unchanged when any conversion failed, check the incompatibility in that case. Fixes https://github.com/ruby/stringio/issues/13 https://github.com/ruby/stringio/commit/ede6bdcc71
-rw-r--r--ext/stringio/stringio.c7
-rw-r--r--test/stringio/test_stringio.rb25
2 files changed, 31 insertions, 1 deletions
diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index b32a391b98..61a6b9a47c 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -1435,7 +1435,12 @@ strio_write(VALUE self, VALUE str)
enc = get_enc(ptr);
enc2 = rb_enc_get(str);
if (enc != enc2 && enc != ascii8bit) {
- str = rb_str_conv_enc(str, enc2, enc);
+ VALUE converted = rb_str_conv_enc(str, enc2, enc);
+ if (converted == str && enc2 != ascii8bit) { /* conversion failed */
+ rb_enc_check(rb_enc_from_encoding(enc), str);
+ UNREACHABLE;
+ }
+ str = converted;
}
len = RSTRING_LEN(str);
if (len == 0) return 0;
diff --git a/test/stringio/test_stringio.rb b/test/stringio/test_stringio.rb
index a99ccf4302..3cf7f42bc5 100644
--- a/test/stringio/test_stringio.rb
+++ b/test/stringio/test_stringio.rb
@@ -187,6 +187,31 @@ class TestStringIO < Test::Unit::TestCase
assert_equal(Encoding::UTF_8, s.encoding, "honor the original encoding over ASCII-8BIT")
end
+ def test_write_encoding_conversion
+ convertible = "\u{3042}"
+ inconvertible = "\u{1f363}"
+ conversion_encoding = Encoding::Windows_31J
+
+ s = StringIO.new.set_encoding(conversion_encoding)
+ s.write(convertible)
+ assert_equal(conversion_encoding, s.string.encoding)
+ all_assertions do |a|
+ [
+ inconvertible,
+ convertible + inconvertible,
+ [convertible, inconvertible],
+ ["a", inconvertible],
+ ].each do |data|
+ a.for(data.inspect) do
+ s = StringIO.new.set_encoding(conversion_encoding)
+ assert_raise(Encoding::CompatibilityError) do
+ s.write(*data)
+ end
+ end
+ end
+ end
+ end
+
def test_write_integer_overflow
f = StringIO.new
f.pos = RbConfig::LIMITS["LONG_MAX"]