This is an automated email from the ASF dual-hosted git repository.
laskoviymishka pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git
The following commit(s) were added to refs/heads/main by this push:
new ac16c2950b Core: Reject negative ByteBuffer stream seeks (#17963)
ac16c2950b is described below
commit ac16c2950b298c8725f57cc8d34f8690d452ef57
Author: Charlie Chen <[email protected]>
AuthorDate: Sat Sep 26 03:09:03 2026 -0700
Core: Reject negative ByteBuffer stream seeks (#17963)
Validate seek positions before resetting buffer state so invalid offsets
fail consistently without changing the current position.
Generated-by: Codex
---
.../apache/iceberg/io/MultiBufferInputStream.java | 2 ++
.../apache/iceberg/io/SingleBufferInputStream.java | 2 ++
.../iceberg/io/TestByteBufferInputStreams.java | 26 ++++++++++++++++++++++
3 files changed, 30 insertions(+)
diff --git
a/core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java
b/core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java
index fae2e615ef..44872b6205 100644
--- a/core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java
+++ b/core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java
@@ -24,6 +24,7 @@ import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.Iterators;
import org.apache.iceberg.relocated.com.google.common.collect.Lists;
@@ -68,6 +69,7 @@ class MultiBufferInputStream extends ByteBufferInputStream {
@Override
public void seek(long newPosition) throws IOException {
+ Preconditions.checkArgument(newPosition >= 0, "Position is negative: %s",
newPosition);
if (newPosition > length) {
throw new EOFException(
String.format("Cannot seek to position after end of file: %s",
newPosition));
diff --git
a/core/src/main/java/org/apache/iceberg/io/SingleBufferInputStream.java
b/core/src/main/java/org/apache/iceberg/io/SingleBufferInputStream.java
index 50431faf7e..2c70cb5a09 100644
--- a/core/src/main/java/org/apache/iceberg/io/SingleBufferInputStream.java
+++ b/core/src/main/java/org/apache/iceberg/io/SingleBufferInputStream.java
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
+import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
/**
* This ByteBufferInputStream does not consume the ByteBuffer being passed in,
but will create a
@@ -82,6 +83,7 @@ class SingleBufferInputStream extends ByteBufferInputStream {
@Override
public void seek(long newPosition) throws IOException {
+ Preconditions.checkArgument(newPosition >= 0, "Position is negative: %s",
newPosition);
if (newPosition > length) {
throw new EOFException(
String.format("Cannot seek to position after end of file: %s",
newPosition));
diff --git
a/core/src/test/java/org/apache/iceberg/io/TestByteBufferInputStreams.java
b/core/src/test/java/org/apache/iceberg/io/TestByteBufferInputStreams.java
index fd2bd6a9d3..4521a2a419 100644
--- a/core/src/test/java/org/apache/iceberg/io/TestByteBufferInputStreams.java
+++ b/core/src/test/java/org/apache/iceberg/io/TestByteBufferInputStreams.java
@@ -362,6 +362,32 @@ public abstract class TestByteBufferInputStreams {
.hasMessageStartingWith("Not enough bytes to skip");
}
+ @Test
+ public void testSeekRejectsNegativePosition() throws Exception {
+ ByteBufferInputStream stream = newStream();
+ assertThat(stream.getPos()).isEqualTo(0);
+
+ assertThatThrownBy(() -> stream.seek(-1))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Position is negative: -1");
+ assertThat(stream.getPos()).isEqualTo(0);
+ assertThat(stream.read()).isGreaterThanOrEqualTo(0);
+ assertThat(stream.getPos()).isEqualTo(1);
+ }
+
+ @Test
+ public void testSeekRejectsNegativePositionWithoutChangingState() throws
Exception {
+ ByteBufferInputStream stream = newStream();
+ assertThat(stream.read()).isGreaterThanOrEqualTo(0);
+
+ assertThatThrownBy(() -> stream.seek(-1))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Position is negative: -1");
+ assertThat(stream.getPos()).isEqualTo(1);
+ assertThat(stream.read()).isGreaterThanOrEqualTo(0);
+ assertThat(stream.getPos()).isEqualTo(2);
+ }
+
@Test
public void testMark() throws Exception {
ByteBufferInputStream stream = newStream();