Fix Marshal.dump(closed_io) to raise TypeError and allow encoding on closed IO

Mashalling a closed IO object raised "closed stream (IOError)" before instead of TypeError.
This changes IO#(in|ex)ternal_encoding to still return the encoding even if the underlying FD is closed.

Fixes bug #18077
This commit is contained in:
Lars Kanis 2021-08-16 13:11:30 +02:00 коммит произвёл Nobuyoshi Nakada
Родитель c527d278a3
Коммит 6594623f62
4 изменённых файлов: 22 добавлений и 8 удалений

6
io.c
Просмотреть файл

@ -12092,9 +12092,8 @@ rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
static VALUE
rb_io_external_encoding(VALUE io)
{
rb_io_t *fptr;
rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
GetOpenFile(io, fptr);
if (fptr->encs.enc2) {
return rb_enc_from_encoding(fptr->encs.enc2);
}
@ -12117,9 +12116,8 @@ rb_io_external_encoding(VALUE io)
static VALUE
rb_io_internal_encoding(VALUE io)
{
rb_io_t *fptr;
rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
GetOpenFile(io, fptr);
if (!fptr->encs.enc2) return Qnil;
return rb_enc_from_encoding(io_read_encoding(fptr));
}

Просмотреть файл

@ -94,8 +94,10 @@ describe "IO#external_encoding" do
rm_r @name
end
it "raises an IOError on closed stream" do
-> { IOSpecs.closed_io.external_encoding }.should raise_error(IOError)
ruby_version_is '3.1' do
it "can be retrieved from a closed stream" do
IOSpecs.closed_io.external_encoding.should equal(Encoding.default_external)
end
end
describe "with 'r' mode" do

Просмотреть файл

@ -113,8 +113,10 @@ describe "IO#internal_encoding" do
Encoding.default_internal = @internal
end
it "raises an IOError on closed stream" do
-> { IOSpecs.closed_io.internal_encoding }.should raise_error(IOError)
ruby_version_is '3.1' do
it "can be retrieved from a closed stream" do
IOSpecs.closed_io.internal_encoding.should equal(Encoding.default_internal)
end
end
describe "with 'r' mode" do

Просмотреть файл

@ -3991,6 +3991,18 @@ __END__
}
end
def test_marshal_closed_io
bug18077 = '[ruby-core:104927] [Bug #18077]'
r, w = IO.pipe
r.close; w.close
assert_raise(TypeError, bug18077) {Marshal.dump(r)}
class << r
undef_method :closed?
end
assert_raise(TypeError, bug18077) {Marshal.dump(r)}
end
def test_stdout_to_closed_pipe
EnvUtil.invoke_ruby(["-e", "loop {puts :ok}"], "", true, true) do
|in_p, out_p, err_p, pid|