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

Reply via email to