oracle/graal · error · BranchTargetOutOfBoundsException
Branch target %d out of bounds
Error message
Branch target %d out of bounds
What it means
Thrown by readPrimitiveArrayUnaligned when offset < 0 or offset + kind.getByteCount() exceeds the Value's buffer size. This mirrors native unaligned read semantics (offset in bytes from the array start) so the guard ensures the full multi-byte read lies inside the buffer.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/asm/aarch64/AArch64MacroAssembler.java:2124
} else {
throw GraalError.shouldNotReachHereUnexpectedValue(instruction); // ExcludeFromJacocoGeneratedReport
}
}
/**
* Patches jump targets when label gets bound.
*/
@Override
protected void patchJumpTarget(int patchPos, int jumpTarget) {
final int instruction = getInt(patchPos);
final int pcRelativeOffset = jumpTarget - patchPos;
assert (pcRelativeOffset & 0b11) == 0 : "unexpected alignment " + pcRelativeOffset;
PatchLabelKind type = PatchLabelKind.fromEncoding(instruction);
final int extraInformation = PatchLabelKind.decodeExtraInformation(instruction);
switch (type) {
case BRANCH_CONDITIONALLY:
if (!NumUtil.isSignedNbit(21, pcRelativeOffset)) {
throw new BranchTargetOutOfBoundsException(true, "Branch target %d out of bounds", pcRelativeOffset);
}
ConditionFlag condition = ConditionFlag.fromEncoding(extraInformation);
super.b(condition, pcRelativeOffset, patchPos);
break;
case BRANCH_UNCONDITIONALLY:
super.b(pcRelativeOffset, patchPos);
break;
case COMPARE_REG_BRANCH_NONZERO:
case COMPARE_REG_BRANCH_ZERO: {
if (!NumUtil.isSignedNbit(21, pcRelativeOffset)) {
throw new BranchTargetOutOfBoundsException(true, "Branch target %d out of bounds", pcRelativeOffset);
}
int regEncoding = extraInformation >>> 1;
int sizeEncoding = extraInformation & 1;
Register reg = AArch64.cpuRegisters.get(regEncoding);
// 1 => 64; 0 => 32
int size = sizeEncoding == 1 ? 64 : 32;
if (type == PatchLabelKind.COMPARE_REG_BRANCH_NONZERO) {View on GitHub (pinned to a66e9ccd1d)
Solutions
- Clamp/validate: require 0 <= offset && offset + kind.getByteCount() <= bufferSize before calling
- Recompute offsets against the guest layout (use the vm access layout API, do not reuse host Unsafe offsets)
- For trailing partial data, read fewer bytes or reject the operation explicitly rather than letting it throw
Example fix
// before
JavaConstant v = vmAccess.readPrimitiveArrayUnaligned(array, JavaKind.Long, offset);
// after
long bufSize = ((EspressoExternalObjectConstant) array).getValue().getBufferSize();
if (offset >= 0 && offset + JavaKind.Long.getByteCount() <= bufSize) {
JavaConstant v = vmAccess.readPrimitiveArrayUnaligned(array, JavaKind.Long, offset);
} else {
throw new IndexOutOfBoundsException("offset " + offset + " out of range for " + bufSize);
} Defensive patterns
Strategy: validation
Validate before calling
long bufSize = ((EspressoExternalObjectConstant) array).getValue().getBufferSize();
int byteCount = kind.getByteCount();
if (offset < 0 || offset + byteCount > bufSize) {
throw new IndexOutOfBoundsException("read [" + offset + "," + (offset + byteCount) + ") outside buffer of " + bufSize);
} Prevention
- Remember offsets are byte offsets into the array's interop buffer, native-endian, matching hosted unaligned reads — do not reuse host Unsafe offsets blindly
- Always check offset + kind.getByteCount() <= bufferSize before the final element of an array
When it happens
Trigger: Negative offsets; offsets near the end of the buffer (e.g. reading a long at len-4); byte offsets computed for a differently-sized array; offsets in element units mistakenly used as byte offsets.
Common situations: Host code ported from Unsafe.getObject-style reads where offsets included object-header constants that differ in the guest; byte-offset math after layout changes between JVM versions; reading the last element with an inclusive-end off-by-one.
Related errors
- Cannot bind label to negative position %d
- Out of scratch registers: %s
- Memory access is outside the boundaries of the allocated mem
- arrayOffset is less than baseOffset
- arrayOffset is beyond array length
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/dfe7233b72f58f70.
Report an issue: GitHub.