Skip to content

fix(buffer): validate offsets in Buffer::into_arrow_offset_buffer - #10292

Open
jianhe25 wants to merge 1 commit into
vortex-data:developfrom
jianhe25:buffer-fix-2
Open

jianhe25 wants to merge 1 commit into
vortex-data:developfrom
jianhe25:buffer-fix-2

Conversation

@jianhe25

@jianhe25 jianhe25 commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

into_arrow_offset_buffer is a safe function, but it called OffsetBuffer::new_unchecked and left the invariants to a doc comment ("SAFETY: The caller should ensure..."). A safe function can't carry unchecked memory-safety preconditions. OffsetBuffer requires non-empty, non-negative-first, monotonically non-decreasing offsets, and breaking that from safe code leads to out-of-bounds reads in downstream Arrow slicing and child indexing.

This switches to the checked OffsetBuffer::new, which panics on invalid input. The signature is unchanged.

Cost: OffsetBuffer::new does an O(n) validation pass. The callers are in vortex-arrow (executor/byte.rs, executor/list.rs). If that cost matters on those paths, the alternative is to make into_arrow_offset_buffer an unsafe fn with a # Safety section and keep new_unchecked. Happy to switch to that.

Testing

  • New tests: valid offsets round-trip zero-copy; a non-zero first offset is accepted (sliced children); decreasing, negative and empty offsets each panic with Arrow's message.
  • cargo test -p vortex-buffer --all-features, cargo test -p vortex-arrow --all-features, clippy, nightly fmt.

AI assistance

This change was prepared with help from an AI coding assistant (Google-internal agentic tooling). I reviewed and verified the change and the tests myself.

`into_arrow_offset_buffer` is a safe function, but it called
`OffsetBuffer::new_unchecked` and pushed the memory-safety requirement onto the caller in
a doc comment:

    /// SAFETY: The caller should ensure that the buffer contains monotonically increasing
    /// values greater than or equal to zero.

A safe function may not carry unchecked memory-safety preconditions. `OffsetBuffer`
requires its contents to be non-empty, to start at a non-negative value and to be
monotonically non-decreasing; safe code that violates those invariants causes
out-of-bounds reads in downstream Arrow operations such as slicing and child-array
indexing.

Use the checked `OffsetBuffer::new` instead. It validates the offsets and panics on bad
input, which is memory-safe. The signature is unchanged, so callers are unaffected.

Signed-off-by: Jian He <hejia@google.com>
///
/// Panics if the buffer is empty, its first offset is negative, or it is not monotonically
/// increasing -- the invariants `OffsetBuffer` requires of its contents.
pub fn into_arrow_offset_buffer(self) -> OffsetBuffer<T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have to adjust the callers to not have to perform revalidation. In general this should perform validation but most of the callers already validated it

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants