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]