Skip to content

Core: Reject negative ByteBuffer stream seeks - #17963

Open
charliec05 wants to merge 1 commit into
apache:mainfrom
charliec05:agent/bytebuffer-negative-seek
Open

Core: Reject negative ByteBuffer stream seeks#17963
charliec05 wants to merge 1 commit into
apache:mainfrom
charliec05:agent/bytebuffer-negative-seek

Conversation

@charliec05

Copy link
Copy Markdown
Contributor

Summary

  • reject negative seek positions in both single- and multi-buffer input streams
  • validate before resetting or advancing buffer state
  • add shared regression coverage that runs against both implementations

Motivation

The two ByteBufferInputStream implementations handled negative positions inconsistently. MultiBufferInputStream silently accepted seek(-1) and reset to the beginning, while SingleBufferInputStream failed later inside ByteBuffer.position after it had already reset its state.

Both implementations now reject the invalid position before changing state, matching the behavior of Iceberg's other seekable streams.

Testing

  • ./gradlew :iceberg-core:spotlessApply :iceberg-core:test
  • ./gradlew :iceberg-core:spotlessCheck :iceberg-core:test --tests org.apache.iceberg.io.TestSingleBufferInputStream --tests org.apache.iceberg.io.TestMultiBufferInputStream

AI Disclosure

  • Model: GPT-5 (Codex)
  • Platform/Tool: OpenAI Codex
  • Human Oversight: fully reviewed
  • Prompt Summary: Used a detailed, repository-aware prompt to compare seek boundary behavior across implementations, reproduce inconsistent negative-position handling, require state preservation, review the minimal diff, and run both focused and complete Core tests.

Validate seek positions before resetting buffer state so invalid offsets fail consistently without changing the current position.

Generated-by: Codex
@github-actions github-actions Bot added the core label Sep 4, 2026
@charliec05

Copy link
Copy Markdown
Contributor Author

Hi @laskoviymishka, would you be willing to review this ByteBufferInputStream boundary fix? It makes both implementations reject negative seeks consistently while preserving stream state, includes shared regression coverage, and all 42 CI checks pass. Thanks!


@Override
public void seek(long newPosition) throws IOException {
Preconditions.checkArgument(newPosition >= 0, "Position is negative: %s", newPosition);

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.

when can this be negative ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

newPosition is supplied by the caller through the public ByteBufferInputStream.wrap(...).seek(...) API. I have not identified a production call path that supplies a negative offset; I found this while testing invalid seek inputs.

On the base revision, after reading the first byte and then calling seek(-1), SingleBufferInputStream throws IllegalArgumentException but has already reset its position to 0, while MultiBufferInputStream accepts the call and also resets to 0. I reproduced both cases: the next read returns the first byte again. With this change, both reject the invalid offset while keeping position 1, and the next read returns the second byte.

The motivation is defensive validation before mutating stream state, consistent with the existing negative-seek guards in EagerInputStream, S3InputStream, and GCSInputStream. The shared regression test checks rejection and position preservation for both implementations.

@uros-b

uros-b commented Sep 5, 2026

Copy link
Copy Markdown
Member

+1 here, please address any additional concerns from committers

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants