Describe the bug, including details regarding any error messages, version, and platform.
ArrowBuf.setBytes(long index, ByteBuffer src, int srcIndex, int length) bound-checks only the
destination (checkIndex(index, length)), never srcIndex/length against src. On the direct
branch it takes the raw buffer address, adds srcIndex, and calls
MemoryUtil.copyMemory(srcAddress, dstAddress, length), so a request whose srcIndex + length
runs past src.capacity() reads off-heap memory beyond the source buffer and copies it into the
ArrowBuf.
The heap branch of the same method rejects the identical request (newBuf.limit(srcIndex + length)
throws), and the sibling overloads all do an unconditional isOutOfBounds check on the other
buffer: setBytes(long, byte[], int, long), setBytes(long, ArrowBuf, long, long),
getBytes(long, byte[], int, int), getBytes(long, ArrowBuf, long, int) and
NettyArrowBuf.setBytes(int, ByteBuf, int, int). This overload is the only one in the family
without one.
Reproducer (bounds checking left at its default, i.e. enabled — the missing check is on the source
side, so BoundsChecking does not cover it):
ByteBuffer backing = ByteBuffer.allocateDirect(32);
for (int i = 0; i < 32; i++) {
backing.put(i, (byte) i);
}
ByteBuffer dup = backing.duplicate();
((Buffer) dup).position(0);
((Buffer) dup).limit(16);
ByteBuffer direct = dup.slice(); // isDirect=true, capacity=16
try (BufferAllocator allocator = new RootAllocator(128);
ArrowBuf buf = allocator.buffer(16)) {
buf.setBytes(0, direct, 8, 16); // asks for src[8, 24) from a 16-byte source
byte[] actual = new byte[16];
buf.getBytes(0, actual);
System.out.println(Arrays.toString(actual));
}
Output:
[8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
The last eight bytes (16..23) are outside the source buffer. The same call with a heap
ByteBuffer raises IllegalArgumentException: newLimit > capacity: (24 > 16), and
buf.setBytes(0, new byte[16], 8, 16) raises IndexOutOfBoundsException.
This overload backs set/setSafe(int, ByteBuffer, int, int) on BaseVariableWidthVector,
BaseLargeVariableWidthVector, BaseVariableWidthViewVector and BaseFixedWidthVector, which
pass start/length straight through, so the adjacent memory lands in vector data that is then
returned to callers or written out over IPC.
Component(s)
Java
Describe the bug, including details regarding any error messages, version, and platform.
ArrowBuf.setBytes(long index, ByteBuffer src, int srcIndex, int length)bound-checks only thedestination (
checkIndex(index, length)), neversrcIndex/lengthagainstsrc. On the directbranch it takes the raw buffer address, adds
srcIndex, and callsMemoryUtil.copyMemory(srcAddress, dstAddress, length), so a request whosesrcIndex + lengthruns past
src.capacity()reads off-heap memory beyond the source buffer and copies it into theArrowBuf.
The heap branch of the same method rejects the identical request (
newBuf.limit(srcIndex + length)throws), and the sibling overloads all do an unconditional
isOutOfBoundscheck on the otherbuffer:
setBytes(long, byte[], int, long),setBytes(long, ArrowBuf, long, long),getBytes(long, byte[], int, int),getBytes(long, ArrowBuf, long, int)andNettyArrowBuf.setBytes(int, ByteBuf, int, int). This overload is the only one in the familywithout one.
Reproducer (bounds checking left at its default, i.e. enabled — the missing check is on the source
side, so
BoundsCheckingdoes not cover it):Output:
The last eight bytes (
16..23) are outside the source buffer. The same call with a heapByteBufferraisesIllegalArgumentException: newLimit > capacity: (24 > 16), andbuf.setBytes(0, new byte[16], 8, 16)raisesIndexOutOfBoundsException.This overload backs
set/setSafe(int, ByteBuffer, int, int)onBaseVariableWidthVector,BaseLargeVariableWidthVector,BaseVariableWidthViewVectorandBaseFixedWidthVector, whichpass
start/lengthstraight through, so the adjacent memory lands in vector data that is thenreturned to callers or written out over IPC.
Component(s)
Java