andygrove opened a new issue, #1417:
URL: https://github.com/apache/arrow-java/issues/1417

   ### Describe the bug, including details regarding any error messages, 
version, and platform.
   
   `DecimalVector` and `Decimal256Vector` have three public write paths that 
copy directly into native memory with `MemoryUtil` rather than through 
`ArrowBuf`, so `ArrowBuf` bounds checking does not apply to them:
   
   - `setBigEndian(int, byte[])` / `setBigEndianSafe(int, byte[])`
   - `setSafe(int, long, ArrowBuf, int length)`
   - `setBigEndianSafe(int, long, ArrowBuf, int length)`
   
   Each of them bounds-checks the 16- or 32-byte destination slot, but none of 
them validates that the *value* length fits in that slot before copying:
   
   - `setBigEndian(int, byte[])` copies all `value.length` bytes on 
little-endian hosts and only then throws `IllegalArgumentException` for lengths 
above `TYPE_WIDTH`. The exception is correct but the overrun has already 
happened.
   - The two `ArrowBuf` variants never check `length` against `TYPE_WIDTH` at 
all, so an oversized `length` is copied past the slot with no exception.
   - The two `ArrowBuf` variants also handle `length == 0` by reading the byte 
at `start - 1` for sign extension, so a zero-length value can decode as -1 
depending on the preceding byte.
   
   Because the value buffer and validity buffer are adjacent slices of one 
allocation, a write of `TYPE_WIDTH + 1` bytes into the last slot of a vector 
clears the first validity byte, which is observable with `isNull()`. Larger 
lengths write beyond the allocation. This happens with the default 
`arrow.enable_unsafe_memory_access=false`.
   
   The same paths are reachable through the generated 
`DecimalWriter.writeBigEndianBytesToDecimal(byte[])` and 
`Decimal256Writer.writeBigEndianBytesToDecimal256(byte[])`, which call 
`setBigEndianSafe` without a length guard.
   
   Reproducer (little-endian host, default bounds checking):
   
   ```java
   try (DecimalVector v = new DecimalVector("d", allocator, 38, 0)) {
     v.allocateNew(64);
     for (int i = 0; i < 8; i++) {
       v.setSafe(i, BigDecimal.valueOf(i));
     }
     int last = v.getValueCapacity() - 1;
     try {
       v.setBigEndianSafe(last, new byte[17]); // throws 
IllegalArgumentException ...
     } catch (IllegalArgumentException expected) {
     }
     v.isNull(0); // ... but is now true: the 17th byte landed in the validity 
buffer
   }
   ```
   
   Version: main (67ef5abf). Platform: macOS arm64, JDK 17.
   
   ### Component(s)
   
   Vector


-- 
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