Skip to content

ArrowBuf.setBytes(long, ByteBuffer, int, int) does not bounds-check the source buffer #1336

Description

@Arawoof06

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

Activity

  1. aryan9948 commented on Oct 8, 2026

    @aryan9948

    Hi @Arawoof06, I'd like to work on this issue. I can investigate the missing source-buffer bounds check in ArrowBuf.setBytes(long, ByteBuffer, int, int), add a regression test, and submit a minimal fix following the existing bounds-checking patterns. Could you assign this issue to me?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions