This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new 1ad95324af [format] Prevent silent truncation of inline blob reads
over 2GB (#8838)
1ad95324af is described below
commit 1ad95324afcd5afae700fcb0a33d765aca4d923f
Author: Arnav Balyan <[email protected]>
AuthorDate: Sun Jul 26 12:46:39 2026 +0530
[format] Prevent silent truncation of inline blob reads over 2GB (#8838)
---
.../format/blob/AbstractBlobElementReader.java | 6 ++
.../format/blob/BlobInlineReadOverflowTest.java | 67 ++++++++++++++++++++++
2 files changed, 73 insertions(+)
diff --git
a/paimon-format/src/main/java/org/apache/paimon/format/blob/AbstractBlobElementReader.java
b/paimon-format/src/main/java/org/apache/paimon/format/blob/AbstractBlobElementReader.java
index ed9e695dfd..51af6d0dc4 100644
---
a/paimon-format/src/main/java/org/apache/paimon/format/blob/AbstractBlobElementReader.java
+++
b/paimon-format/src/main/java/org/apache/paimon/format/blob/AbstractBlobElementReader.java
@@ -64,6 +64,12 @@ abstract class AbstractBlobElementReader implements
BlobElementSerializer.Reader
}
protected final byte[] readInlineBlob(long position, long length) {
+ Preconditions.checkArgument(
+ length <= Integer.MAX_VALUE,
+ "Inline BLOB is too large to read into memory: %s bytes (max
%s). "
+ + "Use 'blob-as-descriptor' = true to read it as a
descriptor.",
+ length,
+ Integer.MAX_VALUE);
byte[] blobData = new byte[(int) length];
SeekableInputStream in = inputStream();
try {
diff --git
a/paimon-format/src/test/java/org/apache/paimon/format/blob/BlobInlineReadOverflowTest.java
b/paimon-format/src/test/java/org/apache/paimon/format/blob/BlobInlineReadOverflowTest.java
new file mode 100644
index 0000000000..930a86b19b
--- /dev/null
+++
b/paimon-format/src/test/java/org/apache/paimon/format/blob/BlobInlineReadOverflowTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.format.blob;
+
+import org.apache.paimon.data.Blob;
+import org.apache.paimon.fs.ByteArraySeekableStream;
+import org.apache.paimon.fs.Path;
+import org.apache.paimon.fs.local.LocalFileIO;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/** Tests reading a BLOB whose inline payload exceeds {@link
Integer#MAX_VALUE} bytes. */
+class BlobInlineReadOverflowTest {
+
+ private static BlobElementSerializer.Reader inlineReader(byte[] onDisk) {
+ return new RawBlobElementSerializer()
+ .createReader(
+ LocalFileIO.create(),
+ new Path("/tmp/does-not-exist.blob"),
+ new ByteArraySeekableStream(onDisk),
+ false);
+ }
+
+ @Test
+ void testOversizedInlineBlobThrowsInsteadOfTruncating() {
+ long declaredLength = (1L << 32) + 16;
+
+ BlobElementSerializer.Reader reader = inlineReader(new byte[16]);
+
+ assertThatThrownBy(() -> reader.read(0, declaredLength))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Inline BLOB is too large")
+ .hasMessageContaining("blob-as-descriptor");
+ }
+
+ @Test
+ void testInlineBlobWithinLimitReadsFully() {
+ byte[] onDisk = new byte[16];
+ for (int i = 0; i < onDisk.length; i++) {
+ onDisk[i] = (byte) i;
+ }
+
+ BlobElementSerializer.Reader reader = inlineReader(onDisk);
+
+ Blob blob = (Blob) reader.read(0, onDisk.length);
+ assertThat(blob.toData()).isEqualTo(onDisk);
+ }
+}