summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@oriontransfer.co.nz>2022-12-23 10:52:10 -0800
committerGitHub <noreply@github.com>2022-12-24 07:52:10 +1300
commit11ad9a42d76ba785b2ec93f327469ead9b810ef4 (patch)
tree92585023c4e099a2658985801ab2b553bc5aebaa
parentaf4cd997a160c4eddc935dd384dbd0160d3160ce (diff)
Fix missing handling of offset argument in `IO::Buffer` `pread` and `pwrite`. (#7012)
Notes
Notes: Merged-By: ioquatix <samuel@codeotaku.com>
-rw-r--r--io_buffer.c22
-rw-r--r--test/ruby/test_io_buffer.rb29
2 files changed, 47 insertions, 4 deletions
diff --git a/io_buffer.c b/io_buffer.c
index 82590be902..d866c967b7 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -1093,6 +1093,8 @@ rb_io_buffer_free(VALUE self)
return self;
}
+// Validate that access to the buffer is within bounds, assuming you want to
+// access length bytes from the specified offset.
static inline void
io_buffer_validate_range(struct rb_io_buffer *data, size_t offset, size_t length)
{
@@ -2510,7 +2512,7 @@ rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t of
struct rb_io_buffer *data = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- io_buffer_validate_range(data, 0, length);
+ io_buffer_validate_range(data, offset, length);
int descriptor = rb_io_descriptor(io);
@@ -2520,8 +2522,14 @@ rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t of
struct io_buffer_pread_internal_argument argument = {
.descriptor = descriptor,
- .base = base,
+
+ // Move the base pointer to the offset:
+ .base = (unsigned char*)base + offset,
+
+ // And the size to the length of data we want to read:
.size = length,
+
+ // From the offset in the file we want to read from:
.offset = from,
};
@@ -2677,7 +2685,7 @@ rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t o
struct rb_io_buffer *data = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- io_buffer_validate_range(data, 0, length);
+ io_buffer_validate_range(data, offset, length);
int descriptor = rb_io_descriptor(io);
@@ -2687,8 +2695,14 @@ rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t o
struct io_buffer_pwrite_internal_argument argument = {
.descriptor = descriptor,
- .base = base,
+
+ // Move the base pointer to the offset:
+ .base = (unsigned char *)base + offset,
+
+ // And the size to the length of data we want to read:
.size = length,
+
+ // And the offset in the file we want to write from:
.offset = from,
};
diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb
index 70070e93c9..d9fa22fd2a 100644
--- a/test/ruby/test_io_buffer.rb
+++ b/test/ruby/test_io_buffer.rb
@@ -373,6 +373,20 @@ class TestIOBuffer < Test::Unit::TestCase
io.close!
end
+ def test_pread_offset
+ io = Tempfile.new
+ io.write("Hello World")
+ io.seek(0)
+
+ buffer = IO::Buffer.new(128)
+ buffer.pread(io, 6, 5, 6)
+
+ assert_equal "World", buffer.get_string(6, 5)
+ assert_equal 0, io.tell
+ ensure
+ io.close!
+ end
+
def test_pwrite
io = Tempfile.new
@@ -388,6 +402,21 @@ class TestIOBuffer < Test::Unit::TestCase
io.close!
end
+ def test_pwrite_offset
+ io = Tempfile.new
+
+ buffer = IO::Buffer.new(128)
+ buffer.set_string("Hello World")
+ buffer.pwrite(io, 6, 5, 6)
+
+ assert_equal 0, io.tell
+
+ io.seek(6)
+ assert_equal "World", io.read(5)
+ ensure
+ io.close!
+ end
+
def test_operators
source = IO::Buffer.for("1234123412")
mask = IO::Buffer.for("133\x00")