diff --git a/io.c b/io.c index a78936488fa50e..3edb15ab7f1be6 100644 --- a/io.c +++ b/io.c @@ -13139,6 +13139,7 @@ copy_stream_fallback_body(VALUE arg) while (1) { long numwrote; long l; + rb_str_make_independent(buf); if (stp->copy_length < (rb_off_t)0) { l = buflen; } diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 999bbd9d2a38dc..3668085d836a24 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -1141,6 +1141,34 @@ def test_copy_stream_pathname_to_pathname } end + def test_copy_stream_dup_buffer + bug21131 = '[ruby-core:120961] [Bug #21131]' + mkcdtmpdir do + dst_class = Class.new do + def initialize(&block) + @block = block + end + + def write(data) + @block.call(data.dup) + data.bytesize + end + end + + rng = Random.new(42) + body = Tempfile.new("ruby-bug", binmode: true) + body.write(rng.bytes(16_385)) + body.rewind + + payload = [] + IO.copy_stream(body, dst_class.new{payload << it}) + body.rewind + assert_equal(body.read, payload.join, bug21131) + ensure + body&.close + end + end + def test_copy_stream_write_in_binmode bug8767 = '[ruby-core:56518] [Bug #8767]' mkcdtmpdir {