MINOR: Check source range in ArrowBuf.setBytes for direct ByteBuffers (#1380) ## What's Changed `ArrowBuf.setBytes(long index, ByteBuffer src, int srcIndex, int length)` bounds-checks only the destination. When `src` is a direct buffer it copies `length` bytes from `getByteBufferAddress(src) + srcIndex` with `MemoryUtil.copyMemory`, so a source range past `src.capacity()` (or a negative `srcIndex`) silently copies adjacent native memory into the ArrowBuf, even with bounds checking enabled. For example, `buf.setBytes(0, ByteBuffer.allocateDirect(8), 0, 64)` succeeds. The heap path already rejects this through `ByteBuffer.position/limit`, and the `byte[]` and `ArrowBuf` overloads (and `NettyArrowBuf.setBytes(ByteBuf)`) check the source with `isOutOfBounds`. This adds the same source check before either path, so the `set/setSafe(int, ByteBuffer, int, int)` methods on the variable-width vectors fail with `IndexOutOfBoundsException` instead of reading out of bounds. Valid ranges behave as before. Added a regression test to `TestArrowBuf`.
diff --git a/memory/memory-core/src/main/java/org/apache/arrow/memory/ArrowBuf.java b/memory/memory-core/src/main/java/org/apache/arrow/memory/ArrowBuf.java index c3eafaa..6bc113e 100644 --- a/memory/memory-core/src/main/java/org/apache/arrow/memory/ArrowBuf.java +++ b/memory/memory-core/src/main/java/org/apache/arrow/memory/ArrowBuf.java
@@ -897,6 +897,12 @@ public void setBytes(long index, ByteBuffer src, int srcIndex, int length) { // bound check for this ArrowBuf where the data will be copied into checkIndex(index, length); + // bound check for src ByteBuffer + if (isOutOfBounds(srcIndex, length, src.capacity())) { + throw new IndexOutOfBoundsException( + String.format( + "index: %d, length: %d (expected: range(0, %d))", srcIndex, length, src.capacity())); + } if (src.isDirect()) { // copy length bytes of data from src ByteBuffer starting at address // srcAddress into this ArrowBuf at address dstAddress
diff --git a/memory/memory-core/src/test/java/org/apache/arrow/memory/TestArrowBuf.java b/memory/memory-core/src/test/java/org/apache/arrow/memory/TestArrowBuf.java index 60e118d..fdb7788 100644 --- a/memory/memory-core/src/test/java/org/apache/arrow/memory/TestArrowBuf.java +++ b/memory/memory-core/src/test/java/org/apache/arrow/memory/TestArrowBuf.java
@@ -112,6 +112,17 @@ } } + @Test + public void testSetBytesDirectOutOfBoundsSource_RaisesIndexOutOfBoundsException() { + ByteBuffer data = ByteBuffer.allocateDirect(8); + try (BufferAllocator allocator = new RootAllocator(128); + ArrowBuf buf = allocator.buffer(64)) { + assertThrows(IndexOutOfBoundsException.class, () -> buf.setBytes(0, data, 0, 64)); + assertThrows(IndexOutOfBoundsException.class, () -> buf.setBytes(0, data, 4, 8)); + assertThrows(IndexOutOfBoundsException.class, () -> buf.setBytes(0, data, -1, 4)); + } + } + /** ARROW-9221: guard against big-endian byte buffers. */ @Test public void testSetBytesBigEndian() {