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

lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-java.git


The following commit(s) were added to refs/heads/main by this push:
     new 3e47560c7 GH-1098: Fix always-true precondition check in 
LargeListVector.setValueCount (#1099)
3e47560c7 is described below

commit 3e47560c773b1bab9d13d446ea69869c782e4666
Author: YangJie <[email protected]>
AuthorDate: Tue Aug 25 11:39:26 2026 +0800

    GH-1098: Fix always-true precondition check in 
LargeListVector.setValueCount (#1099)
    
    ## What's Changed
    
    Fix the precondition check in `LargeListVector.setValueCount()` where
    `||` made the condition always true (`childValueCount <=
    Integer.MAX_VALUE || childValueCount >= Integer.MIN_VALUE` is a
    tautology for any `long` value), allowing silent data corruption when
    `childValueCount` exceeds `Integer.MAX_VALUE` or is negative.
    
    Changes:
    - Replace `||` with `&&` and `Integer.MIN_VALUE` with `0` to correctly
    bound `childValueCount` to `[0, Integer.MAX_VALUE]`, consistent with
    `LargeListViewVector`
    - Add rejection tests for negative and overflow `childValueCount`
    - Add positive boundary tests for zero, valid, and `Integer.MAX_VALUE`
    values
    
    Closes #1098.
---
 .../arrow/vector/complex/LargeListVector.java      |  4 +-
 .../apache/arrow/vector/TestLargeListVector.java   | 89 ++++++++++++++++++++++
 2 files changed, 91 insertions(+), 2 deletions(-)

diff --git 
a/vector/src/main/java/org/apache/arrow/vector/complex/LargeListVector.java 
b/vector/src/main/java/org/apache/arrow/vector/complex/LargeListVector.java
index 92dd3eaef..9368b5ce3 100644
--- a/vector/src/main/java/org/apache/arrow/vector/complex/LargeListVector.java
+++ b/vector/src/main/java/org/apache/arrow/vector/complex/LargeListVector.java
@@ -1041,8 +1041,8 @@ public class LargeListVector extends BaseValueVector
      * TODO: revisit when 64-bit vectors are supported
      */
     Preconditions.checkArgument(
-        childValueCount <= Integer.MAX_VALUE || childValueCount >= 
Integer.MIN_VALUE,
-        "LargeListVector doesn't yet support 64-bit allocations: %s",
+        childValueCount >= 0 && childValueCount <= Integer.MAX_VALUE,
+        "LargeListVector childValueCount must be in [0, Integer.MAX_VALUE] but 
was: %s",
         childValueCount);
     vector.setValueCount((int) childValueCount);
   }
diff --git 
a/vector/src/test/java/org/apache/arrow/vector/TestLargeListVector.java 
b/vector/src/test/java/org/apache/arrow/vector/TestLargeListVector.java
index bf9bba9c7..b6823fbf3 100644
--- a/vector/src/test/java/org/apache/arrow/vector/TestLargeListVector.java
+++ b/vector/src/test/java/org/apache/arrow/vector/TestLargeListVector.java
@@ -21,7 +21,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -29,6 +31,7 @@ import java.util.List;
 import java.util.UUID;
 import org.apache.arrow.memory.ArrowBuf;
 import org.apache.arrow.memory.BufferAllocator;
+import org.apache.arrow.memory.OutOfMemoryException;
 import org.apache.arrow.vector.complex.BaseRepeatedValueVector;
 import org.apache.arrow.vector.complex.LargeListVector;
 import org.apache.arrow.vector.complex.ListVector;
@@ -42,6 +45,7 @@ import org.apache.arrow.vector.types.Types.MinorType;
 import org.apache.arrow.vector.types.pojo.ArrowType;
 import org.apache.arrow.vector.types.pojo.Field;
 import org.apache.arrow.vector.types.pojo.FieldType;
+import org.apache.arrow.vector.util.OversizedAllocationException;
 import org.apache.arrow.vector.util.TransferPair;
 import org.apache.arrow.vector.util.UuidUtility;
 import org.junit.jupiter.api.AfterEach;
@@ -1127,4 +1131,89 @@ public class TestLargeListVector {
     }
     writer.endList();
   }
+
+  @Test
+  public void testSetValueCountRejectsNegativeChildValueCount() {
+    try (final LargeListVector vector = LargeListVector.empty("list", 
allocator)) {
+      vector.addOrGetVector(FieldType.nullable(MinorType.INT.getType()));
+      vector.allocateNew();
+
+      // Write a negative value into the offset buffer to simulate a corrupted 
offset.
+      // The Preconditions check should reject any negative childValueCount.
+      vector.getOffsetBuffer().setLong(LargeListVector.OFFSET_WIDTH, -1L);
+      vector.setLastSet(0);
+
+      assertThrows(
+          IllegalArgumentException.class,
+          () -> vector.setValueCount(1),
+          "setValueCount should reject negative childValueCount");
+    }
+  }
+
+  @Test
+  public void testSetValueCountRejectsOverflowChildValueCount() {
+    try (final LargeListVector vector = LargeListVector.empty("list", 
allocator)) {
+      vector.addOrGetVector(FieldType.nullable(MinorType.INT.getType()));
+      vector.allocateNew();
+
+      // Write a value exceeding Integer.MAX_VALUE into the offset buffer
+      vector.getOffsetBuffer().setLong(LargeListVector.OFFSET_WIDTH, (long) 
Integer.MAX_VALUE + 1L);
+      vector.setLastSet(0);
+
+      assertThrows(
+          IllegalArgumentException.class,
+          () -> vector.setValueCount(1),
+          "setValueCount should reject childValueCount exceeding 
Integer.MAX_VALUE");
+    }
+  }
+
+  @Test
+  public void testSetValueCountAcceptsZeroChildValueCount() {
+    try (final LargeListVector vector = LargeListVector.empty("list", 
allocator)) {
+      vector.addOrGetVector(FieldType.nullable(MinorType.INT.getType()));
+      vector.allocateNew();
+
+      // childValueCount = 0 when valueCount = 0 (no elements)
+      vector.setValueCount(0);
+      assertEquals(0, vector.getValueCount());
+    }
+  }
+
+  @Test
+  public void testSetValueCountAcceptsValidChildValueCount() {
+    try (final LargeListVector vector = LargeListVector.empty("list", 
allocator)) {
+      vector.addOrGetVector(FieldType.nullable(MinorType.INT.getType()));
+      vector.allocateNew();
+
+      // Write a valid childValueCount (5) into the offset buffer
+      vector.getOffsetBuffer().setLong(LargeListVector.OFFSET_WIDTH, 5L);
+      vector.setLastSet(0);
+      vector.setValueCount(1);
+      assertEquals(1, vector.getValueCount());
+    }
+  }
+
+  @Test
+  public void testSetValueCountAcceptsMaxIntChildValueCount() {
+    try (final LargeListVector vector = LargeListVector.empty("list", 
allocator)) {
+      vector.addOrGetVector(FieldType.nullable(MinorType.INT.getType()));
+      vector.allocateNew();
+
+      // Write Integer.MAX_VALUE into the offset buffer to verify the upper 
boundary is inclusive.
+      // The Preconditions check should accept this value (not throw 
IllegalArgumentException).
+      // The child vector may throw OversizedAllocationException due to memory 
limits,
+      // which is expected and unrelated to the precondition validation.
+      vector.getOffsetBuffer().setLong(LargeListVector.OFFSET_WIDTH, 
Integer.MAX_VALUE);
+      vector.setLastSet(0);
+      try {
+        vector.setValueCount(1);
+      } catch (IllegalArgumentException e) {
+        fail("setValueCount should not reject childValueCount = 
Integer.MAX_VALUE", e);
+      } catch (OversizedAllocationException | OutOfMemoryException e) {
+        // OversizedAllocationException or other allocation errors are expected
+        // when trying to allocate Integer.MAX_VALUE elements — this is fine,
+        // the precondition check itself passed.
+      }
+    }
+  }
 }

Reply via email to