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

  1. Clamp/validate: require 0 <= offset && offset + kind.getByteCount() <= bufferSize before calling
  2. Recompute offsets against the guest layout (use the vm access layout API, do not reuse host Unsafe offsets)
  3. 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

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


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/dfe7233b72f58f70. Report an issue: GitHub.