From 35bf6603372360c7680653328274a670fa1d9f38 Mon Sep 17 00:00:00 2001 From: Kasumi Hanazuki Date: Thu, 7 Nov 2024 05:55:39 +0900 Subject: io_buffer.c: Allow copies between overlapping buffers with #copy and #set_string (#11640) The current implementation of `IO::Buffer#copy` and `#set_string` has an undefined behavior when the source and destination memory overlaps, due to the underlying use of the `memcpy` C function. This patch guarantees the methods to be safe even when copying between overlapping buffers by replacing `memcpy` with `memmove`, Fixes: [Bug #20745] --- test/ruby/test_io_buffer.rb | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'test/ruby') diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb index 178ed05003..55296c1f23 100644 --- a/test/ruby/test_io_buffer.rb +++ b/test/ruby/test_io_buffer.rb @@ -633,4 +633,54 @@ class TestIOBuffer < Test::Unit::TestCase end end end + + def test_copy_overlapped_fwd + buf = IO::Buffer.for('0123456789').dup + buf.copy(buf, 3, 7) + assert_equal '0120123456', buf.get_string + end + + def test_copy_overlapped_bwd + buf = IO::Buffer.for('0123456789').dup + buf.copy(buf, 0, 7, 3) + assert_equal '3456789789', buf.get_string + end + + def test_copy_null_destination + buf = IO::Buffer.new(0) + assert_predicate buf, :null? + buf.copy(IO::Buffer.for('a'), 0, 0) + assert_predicate buf, :empty? + end + + def test_copy_null_source + buf = IO::Buffer.for('a').dup + src = IO::Buffer.new(0) + assert_predicate src, :null? + buf.copy(src, 0, 0) + assert_equal 'a', buf.get_string + end + + def test_set_string_overlapped_fwd + str = +'0123456789' + IO::Buffer.for(str) do |buf| + buf.set_string(str, 3, 7) + end + assert_equal '0120123456', str + end + + def test_set_string_overlapped_bwd + str = +'0123456789' + IO::Buffer.for(str) do |buf| + buf.set_string(str, 0, 7, 3) + end + assert_equal '3456789789', str + end + + def test_set_string_null_destination + buf = IO::Buffer.new(0) + assert_predicate buf, :null? + buf.set_string('a', 0, 0) + assert_predicate buf, :empty? + end end -- cgit v1.2.3