From 6594623f623a0982da62cc105094da0701d499da Mon Sep 17 00:00:00 2001 From: Lars Kanis Date: Mon, 16 Aug 2021 13:11:30 +0200 Subject: [PATCH] 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 --- io.c | 6 ++---- spec/ruby/core/io/external_encoding_spec.rb | 6 ++++-- spec/ruby/core/io/internal_encoding_spec.rb | 6 ++++-- test/ruby/test_io.rb | 12 ++++++++++++ 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/io.c b/io.c index 533542b297..2e4c335aae 100644 --- a/io.c +++ b/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)); } diff --git a/spec/ruby/core/io/external_encoding_spec.rb b/spec/ruby/core/io/external_encoding_spec.rb index c1b727d930..25af11f686 100644 --- a/spec/ruby/core/io/external_encoding_spec.rb +++ b/spec/ruby/core/io/external_encoding_spec.rb @@ -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 diff --git a/spec/ruby/core/io/internal_encoding_spec.rb b/spec/ruby/core/io/internal_encoding_spec.rb index 210e969c7b..c76c9c8508 100644 --- a/spec/ruby/core/io/internal_encoding_spec.rb +++ b/spec/ruby/core/io/internal_encoding_spec.rb @@ -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 diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index f7240c4cf6..a90140fd0b 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -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|