jbonofre commented on code in PR #1376:
URL: https://github.com/apache/arrow-java/pull/1376#discussion_r4480640069


##########
vector/src/main/java/org/apache/arrow/vector/util/VectorAppender.java:
##########
@@ -366,6 +369,10 @@ public ValueVector visit(BaseVariableWidthViewVector 
deltaVector, Void value) {
 
     // append view buffer
     ArrowBuf targetViewBuffer = targetVector.getDataBuffer();
+    deltaVector
+        .getDataBuffer()
+        .checkBytes(
+            0, (long) BaseVariableWidthViewVector.ELEMENT_SIZE * 
deltaVector.getValueCount());

Review Comment:
   By the time this check runs, the delta variadic data buffers have already 
been retained and added to the target `dataBuffers`, and the validity bits have 
been appended. If it throws, the target keeps those buffers: they stay pinned 
until the target is closed, they are written out as extra variadic buffers on 
the next IPC write of the target, and every retry adds more.
   
   Can we move this check (plus a validity check) above the capacity loop, 
before the `retain()`/`addAll()`, using `checkCapacity` so a rejected delta 
leaves the target untouched:
   
   ```java
   checkCapacity(
       deltaVector.getDataBuffer(),
       (long) BaseVariableWidthViewVector.ELEMENT_SIZE * 
deltaVector.getValueCount(),
       "view");
   ```



##########
vector/src/main/java/org/apache/arrow/vector/util/VectorAppender.java:
##########
@@ -99,6 +99,9 @@ public ValueVector visit(BaseFixedWidthVector deltaVector, 
Void value) {
           deltaVector.getValueCount(),
           targetVector.getDataBuffer());
     } else {
+      deltaVector
+          .getDataBuffer()
+          .checkBytes(0, (long) deltaVector.getTypeWidth() * 
deltaVector.getValueCount());

Review Comment:
   This check runs after the target has already been reallocated to 
`newValueCount` and after `concatBits` has copied the delta validity bits into 
the target. So a malformed delta (e.g. an IPC delta dictionary whose field node 
claims ~2^30 values over a 4-byte data buffer) can force a multi GB 
reallocation of the target before it is rejected, and if that allocation 
succeeds the target is left with stray validity bits past its value count.
   
   #1364 uses the opposite order for the variable width paths: `validateDelta` 
runs before the target is touched, so a rejected delta leaves the target 
unchanged.
   
   Could we do the same here, right after the `getValueCount() == 0` early 
return? Something like:
   
   ```java
   int deltaCount = deltaVector.getValueCount();
   checkCapacity(
       deltaVector.getValidityBuffer(),
       BitVectorHelper.getValidityBufferSizeFromCount(deltaCount),
       "validity");
   long dataSize =
       deltaVector instanceof BitVector
           ? BitVectorHelper.getValidityBufferSizeFromCount(deltaCount)
           : (long) deltaVector.getTypeWidth() * deltaCount;
   checkCapacity(deltaVector.getDataBuffer(), dataSize, "data");
   ```
   
   The union (line 682) and dense union (line 748) type buffer checks have the 
same problem: they run after `reAlloc()`. They should move above the capacity 
loop too, e.g. `checkCapacity(deltaVector.getTypeBuffer(), (long) 
deltaVector.getValueCount() * UnionVector.TYPE_WIDTH, "type")`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to