Skip to content

Commit

Permalink
IO::Buffer#resize: Free internal buffer if new size is zero (#7569)
Browse files Browse the repository at this point in the history
`#resize(0)` on an IO::Buffer with internal buffer allocated will
result in calling `realloc(data->base, 0)`. The behavior of `realloc`
with size = 0 is implementation-defined (glibc frees the object
and returns NULL, while BSDs return an inaccessible object). And
thus such usage is deprecated in standard C (upcoming C23 will make it
UB).

To avoid this problem, just `free`s the memory when the new size is zero.
  • Loading branch information
hanazuki committed Mar 24, 2023
1 parent 59c3fac commit 09295ea
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 0 deletions.
5 changes: 5 additions & 0 deletions io_buffer.c
Expand Up @@ -1422,6 +1422,11 @@ rb_io_buffer_resize(VALUE self, size_t size)
#endif

if (data->flags & RB_IO_BUFFER_INTERNAL) {
if (size == 0) {
io_buffer_free(data);
return;
}

void *base = realloc(data->base, size);

if (!base) {
Expand Down
18 changes: 18 additions & 0 deletions test/ruby/test_io_buffer.rb
Expand Up @@ -156,6 +156,24 @@ def test_resize_preserve
assert_equal message, buffer.get_string(0, message.bytesize)
end

def test_resize_zero_internal
buffer = IO::Buffer.new(1)

buffer.resize(0)
assert_equal 0, buffer.size

buffer.resize(1)
assert_equal 1, buffer.size
end

def test_resize_zero_external
buffer = IO::Buffer.for('1')

assert_raise IO::Buffer::AccessError do
buffer.resize(0)
end
end

def test_compare_same_size
buffer1 = IO::Buffer.new(1)
assert_equal buffer1, buffer1
Expand Down

0 comments on commit 09295ea

Please sign in to comment.