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

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-11859-3f1668719ddb1aabce05483249cc3c2eec5d1592
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git

commit 8953c9014c487676561b80a1e8a8c86ea44066bb
Author: Matt Van Horn <[email protected]>
AuthorDate: Mon Oct 26 04:09:33 2026 +0000

    fix(array-data): return an error on FixedSizeList validation overflow 
(#11859)
    
    # Which issue does this PR close?
    
    - Closes #11851
    
    # Rationale for this change
    
    Validating a fixed-size list panics when length plus offset, multiplied
    by the list width, exceeds the largest address-sized integer. Array-data
    validation aborts the process. The expected child length is that
    product. checked_len_plus_offset already returns an error when the sum
    overflows. The following checked_mul(list_size) uses expect, so an
    overflowing product panics.
    
    When checked_mul returns None, validation returns
    ArrowError::InvalidArgumentError. The message names the data type, the
    length-plus-offset value, and the list size, and states that the product
    exceeds usize. The added test uses an empty child with no null buffer,
    checks two length and offset pairs whose product overflows, and checks a
    fitting product that reports the child as shorter than required.
    
    # What changes are included in this PR?
    
    Covered in the summary above.
    
    # Are these changes tested?
    
    cargo test -q --manifest-path arrow-data/Cargo.toml -p arrow-data
    reported 86 passed and 0 failed.
    The same cargo test command reported 13 passed and 0 failed in the
    following suite.
    The same cargo test command ran the doctests.
    
    # Are there any significant user-facing changes?
    
    Covered in the summary above.
    
    AI was used for assistance.
    
    Co-authored-by: Matt Van Horn <[email protected]>
    Co-authored-by: RIchard Baah <[email protected]>
---
 arrow-data/src/data.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 3 deletions(-)

diff --git a/arrow-data/src/data.rs b/arrow-data/src/data.rs
index f1f1621fab..c8063c6cc5 100644
--- a/arrow-data/src/data.rs
+++ b/arrow-data/src/data.rs
@@ -1289,9 +1289,12 @@ impl ArrayData {
 
                 let len_plus_offset =
                     checked_len_plus_offset(&self.data_type, self.len, 
self.offset)?;
-                let expected_values_len = len_plus_offset
-                    .checked_mul(list_size)
-                    .expect("integer overflow computing expected number of 
expected values in FixedListSize");
+                let expected_values_len = 
len_plus_offset.checked_mul(list_size).ok_or_else(|| {
+                    ArrowError::InvalidArgumentError(format!(
+                        "Integer overflow computing expected number of values 
in {}: length + offset ({}) multiplied by list size ({}) exceeds usize",
+                        self.data_type, len_plus_offset, list_size
+                    ))
+                })?;
 
                 if values_data.len < expected_values_len {
                     return Err(ArrowError::InvalidArgumentError(format!(
@@ -2719,6 +2722,62 @@ mod tests {
         }
     }
 
+    #[test]
+    fn test_fixed_size_list_validation_child_len_mul_overflow() {
+        // Empty child and no parent null buffer: huge logical lengths 
allocate nothing.
+        let child = ArrayData::builder(DataType::Int32)
+            .len(0)
+            .add_buffer(Buffer::from_slice_ref([0i32; 0]))
+            .build()
+            .unwrap();
+        let list_size = 2i32;
+        let data_type = DataType::FixedSizeList(
+            Arc::new(Field::new("item", DataType::Int32, true)),
+            list_size,
+        );
+        // `(len + offset) * list_size` overflows; the addition itself does 
not.
+        let len_plus_offset = (usize::MAX / 2) + 1;
+        let overflow_cases = [(len_plus_offset, 0usize), (usize::MAX / 2, 1)];
+
+        for (len, offset) in overflow_cases {
+            let err = ArrayData::builder(data_type.clone())
+                .len(len)
+                .offset(offset)
+                .add_child_data(child.clone())
+                .build()
+                .unwrap_err();
+
+            match err {
+                ArrowError::InvalidArgumentError(msg) => assert_eq!(
+                    msg,
+                    format!(
+                        "Integer overflow computing expected number of values 
in {data_type}: length + offset ({len_plus_offset}) multiplied by list size 
({list_size}) exceeds usize"
+                    )
+                ),
+                other => panic!("unexpected error type {other}"),
+            }
+        }
+
+        // Same product is representable here, so validation reports a short 
child.
+        let err = ArrayData::builder(data_type.clone())
+            .len(usize::MAX / 2)
+            .offset(0)
+            .add_child_data(child)
+            .build()
+            .unwrap_err();
+
+        match err {
+            ArrowError::InvalidArgumentError(msg) => assert_eq!(
+                msg,
+                format!(
+                    "Values length 0 is less than the length + offset ({}) 
multiplied by the value size ({list_size}) for {data_type}",
+                    usize::MAX / 2
+                )
+            ),
+            other => panic!("unexpected error type {other}"),
+        }
+    }
+
     #[test]
     fn test_struct_equal_accounts_for_parent_offset() {
         let data_type =

Reply via email to