You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by ie...@apache.org on 2026/04/30 19:08:18 UTC

(avro) 02/03: AVRO-4241: [Java] Simplify no-op validatioin code and fix possible int overflow per PR comments

This is an automated email from the ASF dual-hosted git repository.

iemejia pushed a commit to branch AVRO-4241-binarydecoder-verify-available-bytes-before-read
in repository https://gitbox.apache.org/repos/asf/avro.git

commit f054db4b761ce67d8f1fcfa568e488471adbeff8
Author: Ismaël Mejía <ie...@gmail.com>
AuthorDate: Thu Apr 30 20:43:17 2026 +0200

    AVRO-4241: [Java] Simplify no-op validatioin code and fix possible int overflow per PR comments
---
 .../apache/avro/generic/GenericDatumReader.java    | 32 ++++++++++------------
 .../java/org/apache/avro/io/BinaryDecoder.java     |  3 +-
 2 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
index e09dc95d2d..178ca50cca 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
@@ -324,9 +324,7 @@ public class GenericDatumReader<D> implements DatumReader<D> {
    */
   private long arrayNext(ResolvingDecoder in, Schema elementType) throws IOException {
     long l = in.arrayNext();
-    if (l > 0) {
-      ensureAvailableCollectionBytes(in, l, elementType);
-    }
+    ensureAvailableCollectionBytes(in, l, elementType);
     return l;
   }
 
@@ -365,9 +363,7 @@ public class GenericDatumReader<D> implements DatumReader<D> {
     long l = in.readMapStart();
     LogicalType logicalType = eValue.getLogicalType();
     Conversion<?> conversion = getData().getConversionFor(logicalType);
-    if (l > 0) {
-      ensureAvailableMapBytes(in, l, eValue);
-    }
+    ensureAvailableMapBytes(in, l, eValue);
     Object map = newMap(old, (int) l);
     if (l > 0) {
       do {
@@ -392,9 +388,7 @@ public class GenericDatumReader<D> implements DatumReader<D> {
    */
   private long mapNext(ResolvingDecoder in, Schema valueType) throws IOException {
     long l = in.mapNext();
-    if (l > 0) {
-      ensureAvailableMapBytes(in, l, valueType);
-    }
+    ensureAvailableMapBytes(in, l, valueType);
     return l;
   }
 
@@ -404,14 +398,15 @@ public class GenericDatumReader<D> implements DatumReader<D> {
    * per entry is {@code 1 + minBytesPerElement(valueSchema)}.
    */
   private static void ensureAvailableMapBytes(Decoder decoder, long count, Schema valueSchema) throws EOFException {
+    if (count <= 0) {
+      return;
+    }
     // Map keys are always strings: at least 1 byte for the length varint
-    int minBytesPerEntry = 1 + minBytesPerElement(valueSchema);
-    if (count > 0) {
-      int remaining = decoder.remainingBytes();
-      if (remaining >= 0 && count * (long) minBytesPerEntry > remaining) {
-        throw new EOFException("Map claims " + count + " entries with at least " + minBytesPerEntry
-            + " bytes each, but only " + remaining + " bytes are available");
-      }
+    long minBytesPerEntry = 1L + minBytesPerElement(valueSchema);
+    int remaining = decoder.remainingBytes();
+    if (remaining >= 0 && count * minBytesPerEntry > remaining) {
+      throw new EOFException("Map claims " + count + " entries with at least " + minBytesPerEntry
+          + " bytes each, but only " + remaining + " bytes are available");
     }
   }
 
@@ -490,8 +485,11 @@ public class GenericDatumReader<D> implements DatumReader<D> {
    */
   private static void ensureAvailableCollectionBytes(Decoder decoder, long count, Schema elementSchema)
       throws EOFException {
+    if (count <= 0) {
+      return;
+    }
     int minBytes = minBytesPerElement(elementSchema);
-    if (minBytes > 0 && count > 0) {
+    if (minBytes > 0) {
       int remaining = decoder.remainingBytes();
       if (remaining >= 0 && count * (long) minBytes > remaining) {
         throw new EOFException("Collection claims " + count + " elements with at least " + minBytes
diff --git a/lang/java/avro/src/main/java/org/apache/avro/io/BinaryDecoder.java b/lang/java/avro/src/main/java/org/apache/avro/io/BinaryDecoder.java
index 22d86ca650..77fc849076 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/io/BinaryDecoder.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/io/BinaryDecoder.java
@@ -961,7 +961,8 @@ public class BinaryDecoder extends Decoder {
       int buffered = ba.getLim() - ba.getPos();
       try {
         if (in.getClass() == ByteArrayInputStream.class || in.getClass() == ByteBufferInputStream.class) {
-          return buffered + in.available();
+          long total = (long) buffered + in.available();
+          return (int) Math.min(total, Integer.MAX_VALUE);
         }
       } catch (IOException e) {
         return -1;