From 84e328ebd5faa5ea9f721506d2d0d1820d9dc683 Mon Sep 17 00:00:00 2001 From: Raz Luvaton <16746759+rluvaton@users.noreply.github.com> Date: Wed, 4 Mar 2026 22:21:02 +0200 Subject: [PATCH 1/2] fix: first next_back() on new RowsIter panics --- arrow-row/src/lib.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/arrow-row/src/lib.rs b/arrow-row/src/lib.rs index 9679c89b4807..1df79d3af44b 100644 --- a/arrow-row/src/lib.rs +++ b/arrow-row/src/lib.rs @@ -1415,7 +1415,7 @@ impl DoubleEndedIterator for RowsIter<'_> { return None; } // Safety: We have checked that `start` is less than `end` - let row = unsafe { self.rows.row_unchecked(self.end) }; + let row = unsafe { self.rows.row_unchecked(self.end - 1) }; self.end -= 1; Some(row) } @@ -5651,4 +5651,40 @@ mod tests { .contains("not yet implemented") ); } + + #[test] + fn empty_row_iter_next_back() { + let rows = RowConverter::new(vec![SortField::new(DataType::UInt8)]) + .unwrap() + .empty_rows(0, 0); + let mut rows_iter = rows.iter(); + assert_eq!(rows_iter.next_back(), None); + assert_eq!(rows_iter.next_back(), None); + assert_eq!(rows_iter.next_back(), None); + } + + #[test] + fn row_iter_next_back() { + let row_converter = RowConverter::new(vec![SortField::new(DataType::UInt8)]).unwrap(); + let mut rng = StdRng::seed_from_u64(42); + let array = generate_primitive_array::(&mut rng, 100, 0.8); + let rows = row_converter.convert_columns(&[Arc::new(array)]).unwrap(); + + let mut rows_iter = rows.iter(); + let mut bytes: Vec = vec![]; + + while let Some(row) = rows_iter.next_back() { + bytes.extend(row.data.iter().rev()); + } + + bytes.reverse(); + + assert_eq!( + bytes, + &rows.buffer.as_slice()[..*rows.offsets.last().unwrap()] + ); + + assert_eq!(rows_iter.next_back(), None); + assert_eq!(rows_iter.next(), None); + } } From 2977d07b661c47ca2935be1239e9fd381ed7b3a6 Mon Sep 17 00:00:00 2001 From: Raz Luvaton <16746759+rluvaton@users.noreply.github.com> Date: Thu, 5 Mar 2026 11:28:24 +0200 Subject: [PATCH 2/2] do -1 first, and update safety comment --- arrow-row/src/lib.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arrow-row/src/lib.rs b/arrow-row/src/lib.rs index 1df79d3af44b..078c4574775d 100644 --- a/arrow-row/src/lib.rs +++ b/arrow-row/src/lib.rs @@ -1414,9 +1414,12 @@ impl DoubleEndedIterator for RowsIter<'_> { if self.end == self.start { return None; } - // Safety: We have checked that `start` is less than `end` - let row = unsafe { self.rows.row_unchecked(self.end - 1) }; + self.end -= 1; + + // Safety: By construction we create `end >= start`, so if `end` is not equal to `start` it cannot be less than `start` + // therefore `end - 1` is within range + let row = unsafe { self.rows.row_unchecked(self.end) }; Some(row) } }