[ruby-core:120961] [Ruby master Bug#21131] IO.copy_stream: yielded string changes value when duped

Issue #21131 has been reported by chucke (Tiago Cardoso). ---------------------------------------- Bug #21131: IO.copy_stream: yielded string changes value when duped https://bugs.ruby-lang.org/issues/21131 * Author: chucke (Tiago Cardoso) * Status: Open * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-darwin23] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- I found an odd situation, when using IO.copy_stream with a File writer quack class, where the data passed to #write somehow ends overwritten, despite the instance being duped. class ProcIO def initialize(block) @block = block end # Implementation the IO write protocol, which yield the given chunk to +@block+. 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 = [] block = ->(data){ payload << data.dup } IO.copy_stream(body, ProcIO.new(block)) body.rewind if payload.join != body.read puts "it's a bug" end if you use the debugger, you'll see that the first yielded chunk has the correct bytes when yielded the first time, but when the second 1 byte chunk is yielded (IO.copy_stream reads in chunks of 16384 bytes), the first chunk string value suddenly changes. This should not happen, as the first yielded chunk was a string duped from the string yielded by IO.copy_stream (which is expected to be a buffer). -- https://bugs.ruby-lang.org/

Issue #21131 has been updated by jeremyevans0 (Jeremy Evans). Backport changed from 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN to 3.1: REQUIRED, 3.2: REQUIRED, 3.3: REQUIRED, 3.4: REQUIRED Thank you for the report. This is definitely a bug. My testing shows it affects all versions of Ruby, at least back to 1.9.3. I submitted a PR to fix this issue: https://github.com/ruby/ruby/pull/12771 ---------------------------------------- Bug #21131: IO.copy_stream: yielded string changes value when duped https://bugs.ruby-lang.org/issues/21131#change-112018 * Author: chucke (Tiago Cardoso) * Status: Open * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-darwin23] * Backport: 3.1: REQUIRED, 3.2: REQUIRED, 3.3: REQUIRED, 3.4: REQUIRED ---------------------------------------- I found an odd situation, when using IO.copy_stream with a File writer quack class, where the data passed to #write somehow ends overwritten, despite the instance being duped. class ProcIO def initialize(block) @block = block end # Implementation the IO write protocol, which yield the given chunk to +@block+. 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 = [] block = ->(data){ payload << data.dup } IO.copy_stream(body, ProcIO.new(block)) body.rewind if payload.join != body.read puts "it's a bug" end if you use the debugger, you'll see that the first yielded chunk has the correct bytes when yielded the first time, but when the second 1 byte chunk is yielded (IO.copy_stream reads in chunks of 16384 bytes), the first chunk string value suddenly changes. This should not happen, as the first yielded chunk was a string duped from the string yielded by IO.copy_stream (which is expected to be a buffer). -- https://bugs.ruby-lang.org/

Issue #21131 has been updated by chucke (Tiago Cardoso). Thank you jeremy! Was planning to take a stab at it to see if I could do it, but thankful that you jumped in. ---------------------------------------- Bug #21131: IO.copy_stream: yielded string changes value when duped https://bugs.ruby-lang.org/issues/21131#change-112053 * Author: chucke (Tiago Cardoso) * Status: Closed * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-darwin23] * Backport: 3.1: REQUIRED, 3.2: REQUIRED, 3.3: REQUIRED, 3.4: REQUIRED ---------------------------------------- I found an odd situation, when using IO.copy_stream with a File writer quack class, where the data passed to #write somehow ends overwritten, despite the instance being duped. class ProcIO def initialize(block) @block = block end # Implementation the IO write protocol, which yield the given chunk to +@block+. 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 = [] block = ->(data){ payload << data.dup } IO.copy_stream(body, ProcIO.new(block)) body.rewind if payload.join != body.read puts "it's a bug" end if you use the debugger, you'll see that the first yielded chunk has the correct bytes when yielded the first time, but when the second 1 byte chunk is yielded (IO.copy_stream reads in chunks of 16384 bytes), the first chunk string value suddenly changes. This should not happen, as the first yielded chunk was a string duped from the string yielded by IO.copy_stream (which is expected to be a buffer). -- https://bugs.ruby-lang.org/

Issue #21131 has been updated by k0kubun (Takashi Kokubun). Backport changed from 3.1: REQUIRED, 3.2: REQUIRED, 3.3: REQUIRED, 3.4: REQUIRED to 3.1: REQUIRED, 3.2: REQUIRED, 3.3: REQUIRED, 3.4: DONE ruby_3_4 commit:eb8ee7c189d051e656f781ce2775ede1157edd6a. ---------------------------------------- Bug #21131: IO.copy_stream: yielded string changes value when duped https://bugs.ruby-lang.org/issues/21131#change-112176 * Author: chucke (Tiago Cardoso) * Status: Closed * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-darwin23] * Backport: 3.1: REQUIRED, 3.2: REQUIRED, 3.3: REQUIRED, 3.4: DONE ---------------------------------------- I found an odd situation, when using IO.copy_stream with a File writer quack class, where the data passed to #write somehow ends overwritten, despite the instance being duped. class ProcIO def initialize(block) @block = block end # Implementation the IO write protocol, which yield the given chunk to +@block+. 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 = [] block = ->(data){ payload << data.dup } IO.copy_stream(body, ProcIO.new(block)) body.rewind if payload.join != body.read puts "it's a bug" end if you use the debugger, you'll see that the first yielded chunk has the correct bytes when yielded the first time, but when the second 1 byte chunk is yielded (IO.copy_stream reads in chunks of 16384 bytes), the first chunk string value suddenly changes. This should not happen, as the first yielded chunk was a string duped from the string yielded by IO.copy_stream (which is expected to be a buffer). -- https://bugs.ruby-lang.org/

Issue #21131 has been updated by hsbt (Hiroshi SHIBATA). Backport changed from 3.1: REQUIRED, 3.2: REQUIRED, 3.3: REQUIRED, 3.4: DONE to 3.1: REQUIRED, 3.2: DONE, 3.3: REQUIRED, 3.4: DONE ruby_3_2 commit:4e9100b9974df197e569298655d37b8a2fadcfa5 merged revision(s) commit:f423f6e10c0c226dfed98e7cb7a5d489191dfa35. ---------------------------------------- Bug #21131: IO.copy_stream: yielded string changes value when duped https://bugs.ruby-lang.org/issues/21131#change-112278 * Author: chucke (Tiago Cardoso) * Status: Closed * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-darwin23] * Backport: 3.1: REQUIRED, 3.2: DONE, 3.3: REQUIRED, 3.4: DONE ---------------------------------------- I found an odd situation, when using IO.copy_stream with a File writer quack class, where the data passed to #write somehow ends overwritten, despite the instance being duped. class ProcIO def initialize(block) @block = block end # Implementation the IO write protocol, which yield the given chunk to +@block+. 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 = [] block = ->(data){ payload << data.dup } IO.copy_stream(body, ProcIO.new(block)) body.rewind if payload.join != body.read puts "it's a bug" end if you use the debugger, you'll see that the first yielded chunk has the correct bytes when yielded the first time, but when the second 1 byte chunk is yielded (IO.copy_stream reads in chunks of 16384 bytes), the first chunk string value suddenly changes. This should not happen, as the first yielded chunk was a string duped from the string yielded by IO.copy_stream (which is expected to be a buffer). -- https://bugs.ruby-lang.org/

Issue #21131 has been updated by nagachika (Tomoyuki Chikanaga). Backport changed from 3.1: REQUIRED, 3.2: DONE, 3.3: REQUIRED, 3.4: DONE to 3.1: REQUIRED, 3.2: DONE, 3.3: DONE, 3.4: DONE ruby_3_3 commit:f85e5e01bafeca387e833b9d79cab43a8b22aa3d merged revision(s) commit:f423f6e10c0c226dfed98e7cb7a5d489191dfa35. ---------------------------------------- Bug #21131: IO.copy_stream: yielded string changes value when duped https://bugs.ruby-lang.org/issues/21131#change-112355 * Author: chucke (Tiago Cardoso) * Status: Closed * ruby -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-darwin23] * Backport: 3.1: REQUIRED, 3.2: DONE, 3.3: DONE, 3.4: DONE ---------------------------------------- I found an odd situation, when using IO.copy_stream with a File writer quack class, where the data passed to #write somehow ends overwritten, despite the instance being duped. class ProcIO def initialize(block) @block = block end # Implementation the IO write protocol, which yield the given chunk to +@block+. 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 = [] block = ->(data){ payload << data.dup } IO.copy_stream(body, ProcIO.new(block)) body.rewind if payload.join != body.read puts "it's a bug" end if you use the debugger, you'll see that the first yielded chunk has the correct bytes when yielded the first time, but when the second 1 byte chunk is yielded (IO.copy_stream reads in chunks of 16384 bytes), the first chunk string value suddenly changes. This should not happen, as the first yielded chunk was a string duped from the string yielded by IO.copy_stream (which is expected to be a buffer). -- https://bugs.ruby-lang.org/
participants (5)
-
chucke (Tiago Cardoso)
-
hsbt (Hiroshi SHIBATA)
-
jeremyevans0 (Jeremy Evans)
-
k0kubun (Takashi Kokubun)
-
nagachika (Tomoyuki Chikanaga)