From 1bb432cb55ea8a6681ea42d3f667734083804680 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Sun, 21 Jun 2026 20:55:54 +0200 Subject: [PATCH] fix: validate interleave indices --- arrow-select/src/interleave.rs | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/arrow-select/src/interleave.rs b/arrow-select/src/interleave.rs index c3d47980e3c3..6a7aa300a37c 100644 --- a/arrow-select/src/interleave.rs +++ b/arrow-select/src/interleave.rs @@ -95,6 +95,8 @@ pub fn interleave( return Ok(new_empty_array(data_type)); } + validate_interleave_indices(values, indices)?; + downcast_primitive! { data_type => (primitive_helper, values, indices, data_type), DataType::Utf8 => interleave_bytes::(values, indices), @@ -122,6 +124,29 @@ pub fn interleave( } } +fn validate_interleave_indices( + values: &[&dyn Array], + indices: &[(usize, usize)], +) -> Result<(), ArrowError> { + for (index, &(array_idx, row_idx)) in indices.iter().enumerate() { + let array = values.get(array_idx).ok_or_else(|| { + ArrowError::InvalidArgumentError(format!( + "interleave index {index} references array {array_idx}, but only {} arrays were provided", + values.len() + )) + })?; + + if row_idx >= array.len() { + return Err(ArrowError::InvalidArgumentError(format!( + "interleave index {index} references row {row_idx} of array {array_idx}, but the array has length {}", + array.len() + ))); + } + } + + Ok(()) +} + /// Common functionality for interleaving arrays /// /// T is the concrete Array type @@ -889,6 +914,32 @@ mod tests { assert_eq!(v.data_type(), &DataType::Int32); } + #[test] + fn test_interleave_out_of_bounds_array_index() { + let a = Int32Array::from_iter_values([1, 2, 3, 4]); + + let err = interleave(&[&a], &[(1, 0)]).unwrap_err(); + + assert!(matches!( + err, + ArrowError::InvalidArgumentError(message) + if message.contains("references array 1") + )); + } + + #[test] + fn test_interleave_out_of_bounds_row_index() { + let a = Int32Array::from_iter_values([1, 2, 3, 4]); + + let err = interleave(&[&a], &[(0, 4)]).unwrap_err(); + + assert!(matches!( + err, + ArrowError::InvalidArgumentError(message) + if message.contains("references row 4") + )); + } + #[test] fn test_strings() { let a = StringArray::from_iter_values(["a", "b", "c"]); @@ -1536,6 +1587,26 @@ mod tests { ); } + #[test] + fn test_interleave_views_out_of_bounds_row_index() { + let values = StringArray::from_iter_values([ + "hello", + "world_long_string_not_inlined", + "foo", + "bar", + "baz", + ]); + let view = StringViewArray::from(&values); + + let err = interleave(&[&view], &[(0, 5)]).unwrap_err(); + + assert!(matches!( + err, + ArrowError::InvalidArgumentError(message) + if message.contains("references row 5") + )); + } + #[test] fn test_interleave_views_with_nulls() { let values = StringArray::from_iter([