This is an automated email from the ASF dual-hosted git repository.
kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new 12b3eda46a GH-45187: [Ruby] Ensure initializing all rb_memory_view_t
members (#50234)
12b3eda46a is described below
commit 12b3eda46a69fbc2e7f6f9c52be345b678f4baae
Author: Aaditya Srinivasan <[email protected]>
AuthorDate: Wed Jun 24 10:35:44 2026 +0530
GH-45187: [Ruby] Ensure initializing all rb_memory_view_t members (#50234)
### Rationale for this change
`rb_memory_view_get()` callers may pass a non-zero-initialized
`rb_memory_view_t`. `primitive_array_get()` and `buffer_get()` did not
initialize `item_desc.components` and `item_desc.length`, which could cause
`rb_memory_view_release()` to attempt to free an invalid pointer and abort the
process.
### What changes are included in this PR?
This change initializes `item_desc.components` and `item_desc.length` in
both `primitive_array_get()` and `buffer_get()`.
It also adds regression tests that verify releasing a memory view with a
non-zero-initialized `rb_memory_view_t` does not crash for both
`Arrow::Int32Array` and `Arrow::Buffer`.
### Are these changes tested?
Yes. Added regression tests in `test-memory-view.rb` that reproduced the
crash before this change and pass after the fix.
### Are there any user-facing changes?
No.
**This PR contains a "Critical Fix".**
This change fixes a crash that could occur when `rb_memory_view_release()`
is called with a memory view whose `item_desc` members were not initialized.
* GitHub Issue: #45187
Lead-authored-by: Aaditya Srinivasan <[email protected]>
Co-authored-by: Sutou Kouhei <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
---
ruby/red-arrow/ext/arrow/memory-view.cpp | 9 ++----
ruby/red-arrow/test/test-memory-view.rb | 53 ++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/ruby/red-arrow/ext/arrow/memory-view.cpp
b/ruby/red-arrow/ext/arrow/memory-view.cpp
index a3135310c9..3869b45583 100644
--- a/ruby/red-arrow/ext/arrow/memory-view.cpp
+++ b/ruby/red-arrow/ext/arrow/memory-view.cpp
@@ -31,6 +31,7 @@
# undef private
#endif
+#include <cstring>
#include <sstream>
namespace red_arrow {
@@ -220,6 +221,7 @@ namespace red_arrow {
return false;
}
auto view_ = reinterpret_cast<memory_view *>(view);
+ memset(view_, 0, sizeof(memory_view));
view_->obj = obj;
view_->private_data = new PrivateData();
auto array = GARROW_ARRAY(RVAL2GOBJ(obj));
@@ -231,9 +233,6 @@ namespace red_arrow {
}
view_->readonly = true;
view_->ndim = 1;
- view_->shape = NULL;
- view_->strides = NULL;
- view_->sub_offsets = NULL;
return true;
}
@@ -258,6 +257,7 @@ namespace red_arrow {
return false;
}
auto view_ = reinterpret_cast<memory_view *>(view);
+ memset(view_, 0, sizeof(memory_view));
view_->obj = obj;
auto buffer = GARROW_BUFFER(RVAL2GOBJ(obj));
auto arrow_buffer = garrow_buffer_get_raw(buffer);
@@ -275,9 +275,6 @@ namespace red_arrow {
view_->byte_size = arrow_buffer->size();
view_->readonly = true;
view_->ndim = 1;
- view_->shape = NULL;
- view_->strides = NULL;
- view_->sub_offsets = NULL;
return true;
}
diff --git a/ruby/red-arrow/test/test-memory-view.rb
b/ruby/red-arrow/test/test-memory-view.rb
index 0b9c98c407..8aa5728a56 100644
--- a/ruby/red-arrow/test/test-memory-view.rb
+++ b/ruby/red-arrow/test/test-memory-view.rb
@@ -431,4 +431,57 @@ class MemoryViewTest < Test::Unit::TestCase
])
end
end
+
+ sub_test_case("uninitialized rb_memory_view_t") do
+ def setup
+ libruby = Fiddle.dlopen(nil)
+
+ @rb_memory_view_get = Fiddle::Function.new(
+ libruby["rb_memory_view_get"],
+ [
+ Fiddle::TYPE_UINTPTR_T,
+ Fiddle::TYPE_VOIDP,
+ Fiddle::TYPE_INT,
+ ],
+ Fiddle::TYPE_BOOL
+ )
+
+ @rb_memory_view_release = Fiddle::Function.new(
+ libruby["rb_memory_view_release"],
+ [
+ Fiddle::TYPE_VOIDP,
+ ],
+ Fiddle::TYPE_BOOL
+ )
+ end
+
+ def assert_release(target)
+ # We should use sizeof(rb_memory_view_t) but it isn't available from
Ruby.
+ # 256 must be larger than sizeof(rb_memory_view_t).
+ size = 256
+ Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) do |view|
+ size.times do |i|
+ view[i] = 0xAA
+ end
+
+ assert do
+ @rb_memory_view_get.call(Fiddle.dlwrap(target), view, 0)
+ end
+
+ assert do
+ @rb_memory_view_release.call(view)
+ end
+ end
+ end
+
+ test("Int32Array") do
+ array = Arrow::Int32Array.new([1, 2, 3, 4, 5])
+ assert_release(array)
+ end
+
+ test("Buffer") do
+ buffer = Arrow::Buffer.new("hello")
+ assert_release(buffer)
+ end
+ end
end