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 73b05ded07 Prevent `ArrayData::slice` length overflow (#9813)
73b05ded07 is described below

commit 73b05ded074cb91f2c5c0aaa87ecf57f20ffcc4c
Author: Andrew Lamb <[email protected]>
AuthorDate: Wed Apr 29 13:45:47 2026 -0400

    Prevent `ArrayData::slice` length overflow (#9813)
    
    # Which issue does this PR close?
    
    - None.
    
    # Rationale for this change
    
    `ArrayData::slice` checked bounds using unchecked `usize` addition. In
    optimized builds, very large `length` values could wrap `offset +
    length`, allowing invalid slice arguments to create `ArrayData` with
    inconsistent length and offset metadata instead of panicking.
    
    # What changes are included in this PR?
    
    This updates `ArrayData::slice` to use checked arithmetic when computing
    the slice end.
    
    The panic documentation is updated to describe the overflow case.
    
    # Are these changes tested?
    
    Yes. This adds a regression test covering a slice-of-slice call where
    `offset + length` overflows. The new regression was also verified in
    release mode.
    
    Validated with:
    
    ```bash
    cargo test -p arrow-data test_slice_panics_on_offset_length_overflow 
--release
    ```
    
    # Are there any user-facing changes?
    
    Invalid `ArrayData::slice` arguments where `offset + length` overflows
    now panic consistently across build modes. There are no API changes.
---
 arrow-array/src/array/fixed_size_list_array.rs |  2 +-
 arrow-array/src/array/struct_array.rs          |  2 +-
 arrow-data/src/data.rs                         | 20 ++++++++++++++++++--
 3 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/arrow-array/src/array/fixed_size_list_array.rs 
b/arrow-array/src/array/fixed_size_list_array.rs
index 55a9fb9aa4..01ccafd9cc 100644
--- a/arrow-array/src/array/fixed_size_list_array.rs
+++ b/arrow-array/src/array/fixed_size_list_array.rs
@@ -645,7 +645,7 @@ mod tests {
     }
 
     #[test]
-    #[should_panic(expected = "assertion failed: (offset + length) <= 
self.len()")]
+    #[should_panic(expected = "assertion failed: end <= self.len()")]
     // Different error messages, so skip for now
     // https://github.com/apache/arrow-rs/issues/1545
     #[cfg(not(feature = "force_validate"))]
diff --git a/arrow-array/src/array/struct_array.rs 
b/arrow-array/src/array/struct_array.rs
index ba187bdef2..e7626b26d0 100644
--- a/arrow-array/src/array/struct_array.rs
+++ b/arrow-array/src/array/struct_array.rs
@@ -718,7 +718,7 @@ mod tests {
     }
 
     #[test]
-    #[should_panic(expected = "assertion failed: (offset + length) <= 
self.len()")]
+    #[should_panic(expected = "assertion failed: end <= self.len()")]
     fn test_struct_array_from_data_with_offset_and_length_error() {
         let int_arr = Int32Array::from(vec![1, 2, 3, 4, 5]);
         let int_field = Field::new("x", DataType::Int32, false);
diff --git a/arrow-data/src/data.rs b/arrow-data/src/data.rs
index 26f59429ee..34d5cb6d3a 100644
--- a/arrow-data/src/data.rs
+++ b/arrow-data/src/data.rs
@@ -589,9 +589,12 @@ impl ArrayData {
     ///
     /// # Panics
     ///
-    /// Panics if `offset + length > self.len()`.
+    /// Panics if `offset + length` overflows or is greater than `self.len()`.
     pub fn slice(&self, offset: usize, length: usize) -> ArrayData {
-        assert!((offset + length) <= self.len());
+        let end = offset
+            .checked_add(length)
+            .expect("offset + length overflow");
+        assert!(end <= self.len());
 
         if let DataType::Struct(_) = self.data_type() {
             // Slice into children
@@ -2397,6 +2400,19 @@ mod tests {
         assert_eq!(data.null_count() - 1, new_data.null_count());
     }
 
+    #[test]
+    #[should_panic(expected = "offset + length overflow")]
+    fn test_slice_panics_on_offset_length_overflow() {
+        let data = ArrayData::builder(DataType::Int32)
+            .len(4)
+            .add_buffer(make_i32_buffer(4))
+            .build()
+            .unwrap();
+        let sliced = data.slice(1, 3);
+
+        sliced.slice(1, usize::MAX);
+    }
+
     #[test]
     fn test_typed_offsets_length_overflow() {
         let data = ArrayData {

Reply via email to