This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 4e5583273f fix: `Buffer::into_mutable` return error instead of panic 
for converting owned sliced when not start at 0 and fix returned Mutable length 
(#10118)
4e5583273f is described below

commit 4e5583273fb8f308eeb7d21dab979cd4268a502f
Author: Raz Luvaton <[email protected]>
AuthorDate: Wed Jun 24 21:52:05 2026 +0300

    fix: `Buffer::into_mutable` return error instead of panic for converting 
owned sliced when not start at 0 and fix returned Mutable length (#10118)
    
    # Which issue does this PR close?
    
    - Closes #10117
    
    # Rationale for this change
    
    This include 2 fixes:
    
    1. Calling `Buffer::into_mutable` on owned sliced that
    `Buffer::ptr_offset() > 0` panicked before, now returning error
    2. Calling `Buffer::into_mutable` on owned slice that
    `Buffer::ptr_offset() == 0` returned `MutableBuffer` with length greater
    than the original buffer length
    
    # What changes are included in this PR?
    
    1. Updating `Buffer::into_mutable` to return error when `ptr_offset > 0`
    2. Set the returned `MutableBuffer` length to the original buffer length
    so length is the same
    
    # Are these changes tested?
    yes
    
    # Are there any user-facing changes?
    not really, except error instead of panic and correct mutable length
---
 arrow-buffer/src/buffer/immutable.rs | 81 ++++++++++++++++++++++++++++++------
 1 file changed, 68 insertions(+), 13 deletions(-)

diff --git a/arrow-buffer/src/buffer/immutable.rs 
b/arrow-buffer/src/buffer/immutable.rs
index fc001afe5a..9c7fc1a901 100644
--- a/arrow-buffer/src/buffer/immutable.rs
+++ b/arrow-buffer/src/buffer/immutable.rs
@@ -358,8 +358,8 @@ impl Buffer {
         UnalignedBitChunk::new(self.as_slice(), offset, len).count_ones()
     }
 
-    /// Returns `MutableBuffer` for mutating the buffer if this buffer is not 
shared.
-    /// Returns `Err` if this is shared or its allocation is from an external 
source or
+    /// Returns `MutableBuffer` for mutating the buffer if this buffer is not 
shared or sliced.
+    /// Returns `Err` if this is shared or the [`Self::ptr_offset`] is greater 
than 0 or its allocation is from an external source or
     /// it is not allocated with alignment [`ALIGNMENT`]
     ///
     /// # Example: Creating a [`MutableBuffer`] from a [`Buffer`]
@@ -383,17 +383,30 @@ impl Buffer {
     pub fn into_mutable(self) -> Result<MutableBuffer, Self> {
         let ptr = self.ptr;
         let length = self.length;
-        Arc::try_unwrap(self.data)
-            .and_then(|bytes| {
-                // The pointer of underlying buffer should not be offset.
-                assert_eq!(ptr, bytes.ptr().as_ptr());
-                MutableBuffer::from_bytes(bytes).map_err(Arc::new)
-            })
-            .map_err(|bytes| Buffer {
-                data: bytes,
-                ptr,
-                length,
-            })
+
+        // Disallow converting when the offset is not 0 because we can't start 
a mutable from offset
+        let res = if self.ptr_offset() > 0 {
+            Err(self.data)
+        } else {
+            Arc::try_unwrap(self.data)
+        };
+
+        res.and_then(|bytes| {
+            // The pointer of underlying buffer should not be offset.
+            assert_eq!(ptr, bytes.ptr().as_ptr());
+            MutableBuffer::from_bytes(bytes).map_err(Arc::new)
+        })
+        .map_err(|bytes| Buffer {
+            data: bytes,
+            ptr,
+            length,
+        })
+        .map(|mut mutable| {
+            // We need to update the length since in case we are converting 
sliced buffer we need to return MutableBuffer with the same length
+            // SAFETY: this is safe as the length is coming from valid Buffer 
(this) and it is guaranteed to be less than the underlying data buffer
+            unsafe { mutable.set_len(length) };
+            mutable
+        })
     }
 
     /// Converts self into a `Vec`, if possible.
@@ -1080,4 +1093,46 @@ mod tests {
         drop(capture);
         assert_eq!(buffer2.strong_count(), 1);
     }
+
+    #[test]
+    fn 
into_mutable_should_return_error_for_sliced_owned_buffer_when_ptr_offset_is_not_0()
 {
+        let original_buffer_data = [1_u8, 2, 3, 4, 5, 6, 7, 8];
+        for (slice_from, slice_length) in [
+            (original_buffer_data.len(), 0),
+            (2, 4),
+            (2, original_buffer_data.len() - 2),
+        ] {
+            let buffer = Buffer::from(original_buffer_data);
+            let sliced = buffer.slice_with_length(slice_from, slice_length);
+            drop(buffer); // Keep only 1 owner
+            assert_ne!(sliced.ptr_offset(), 0);
+
+            sliced
+                .into_mutable()
+                .expect_err("should not convert sliced buffer when ptr_offset 
is not 0");
+        }
+    }
+
+    #[test]
+    fn 
into_mutable_should_allow_converting_sliced_owned_buffer_when_ptr_offset_is_0() 
{
+        let original_buffer_data = [1_u8, 2, 3, 4, 5, 6, 7, 8];
+        for slice_length in [0, original_buffer_data.len() - 2] {
+            let buffer = Buffer::from(original_buffer_data);
+            let sliced = buffer.slice_with_length(0, slice_length);
+            drop(buffer); // Keep only 1 owner
+            assert_eq!(sliced.ptr_offset(), 0);
+
+            let original_ptr = sliced.data_ptr();
+
+            let mutable = sliced
+                        .into_mutable()
+                        .unwrap_or_else(|_| panic!("should allow converting to 
mutable when not sliced from end when slice_length is {slice_length}"));
+
+            let buffer_back: Buffer = mutable.into();
+            assert_eq!(buffer_back.data_ptr(), original_ptr);
+
+            let expected = 
Buffer::from(original_buffer_data).slice_with_length(0, slice_length);
+            assert_eq!(buffer_back.as_slice(), expected.as_slice());
+        }
+    }
 }

Reply via email to