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();

Reply via email to