{"record":{"id":"da082a55f5202689","repo":"oracle/graal","slug":"invalid-output-range-for-array-of-length","errorCode":null,"errorMessage":"Invalid output range: {}..{} for array of length {}","messagePattern":"Invalid output range: (.+?)\\.\\.(.+?) for array of length (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler.hostvmaccess/src/jdk/graal/compiler/hostvmaccess/HostVMAccess.java","lineNumber":499,"sourceCode":"\n    @Override\n    public void copyMemory(JavaConstant src, int srcFrom, int srcTo, byte[] dst, int dstFrom) {\n        ResolvedJavaType arrayType = getProviders().getMetaAccess().lookupJavaType(src);\n        if (arrayType == null || !arrayType.isArray() || !arrayType.getComponentType().isPrimitive()) {\n            throw new IllegalArgumentException(\"Expected a primitive array constant, got \" + src);\n        }\n        var array = providers.getSnippetReflection().asObject(Object.class, src);\n        if (array == null) {\n            throw new IllegalArgumentException(\"Could not unwrap an array constant: \" + src);\n        }\n        int sourceArrayEnd = Array.getLength(array) * arrayType.getComponentType().getJavaKind().getByteCount();\n        if (srcFrom < 0 || srcTo > sourceArrayEnd || srcTo < srcFrom) {\n            throw new IllegalArgumentException(\n                            \"Invalid input range: \" + srcFrom + \"..\" + srcTo + \" for array of length \" + Array.getLength(array) + \" with kind \" + arrayType.getComponentType().getJavaKind());\n        }\n        int bytesToCopy = srcTo - srcFrom;\n        if (dstFrom < 0 || dstFrom > dst.length - bytesToCopy) {\n            throw new IllegalArgumentException(\"Invalid output range: \" + dstFrom + \"..\" + (dstFrom + bytesToCopy) + \" for array of length \" + dst.length);\n        }\n        var unsafe = Unsafe.getUnsafe();\n        unsafe.copyMemory(array, unsafe.arrayBaseOffset(array.getClass()) + srcFrom, dst, Unsafe.ARRAY_BYTE_BASE_OFFSET + dstFrom, bytesToCopy);\n    }\n\n    /**\n     * Host mode performs the unaligned read with {@link Unsafe} against the unwrapped hosted array\n     * object.\n     */\n    @Override\n    public JavaConstant readPrimitiveArrayUnaligned(JavaConstant primitiveArray, JavaKind kind, int offset) {\n        if (kind == null || !kind.isPrimitive() || kind == JavaKind.Void) {\n            throw new IllegalArgumentException(\"Expected a non-void primitive kind, got \" + kind);\n        }\n        ResolvedJavaType arrayType = getProviders().getMetaAccess().lookupJavaType(primitiveArray);\n        if (arrayType == null || !arrayType.isArray() || !arrayType.getComponentType().isPrimitive()) {\n            throw new IllegalArgumentException(\"Expected a primitive array constant, got \" + primitiveArray);\n        }","sourceCodeStart":481,"sourceCodeEnd":517,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler.hostvmaccess/src/jdk/graal/compiler/hostvmaccess/HostVMAccess.java#L481-L517","documentation":"After validating the source range, copyMemory checks that the destination byte[] can hold bytesToCopy = srcTo - srcFrom starting at dstFrom. This IllegalArgumentException fires when dstFrom is negative or dstFrom + bytesToCopy would run past dst.length — the destination slice is too small for the requested bytes.","triggerScenarios":"Calling copyMemory with a dst byte[] shorter than srcTo - srcFrom, or a dstFrom that leaves insufficient room: dst = new byte[4] while copying 8 bytes from a long[]; or dstFrom near the end of a larger buffer.","commonSituations":"Sizing the output buffer from element count instead of byte count; reusing a fixed-size scratch buffer across arrays of different kinds; forgetting that dstFrom shifts the window.","solutions":["Allocate dst with at least (srcTo - srcFrom) bytes and use dstFrom = 0, or verify dst.length - dstFrom >= srcTo - srcFrom before the call","Derive the buffer size from the component kind's byte count, not the element count","Write a small guard that clamps or rejects the copy when the destination is too small"],"exampleFix":"// before\nbyte[] dst = new byte[4]; // but src is long[1] => 8 bytes\nvmAccess.copyMemory(srcConst, 0, 8, dst, 0);\n\n// after\nint bytes = srcTo - srcFrom;\nbyte[] dst = new byte[bytes];\nvmAccess.copyMemory(srcConst, srcFrom, srcTo, dst, 0);","handlingStrategy":"validation","validationCode":"int bytes = srcTo - srcFrom;\nif (dst == null || dstFrom < 0 || dst.length - dstFrom < bytes) {\n    dst = new byte[bytes]; dstFrom = 0; // or reject\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Size destination buffers from byte counts, never element counts","Allocate dst exactly (srcTo - srcFrom) when you control the call","Keep one shared bounds-check helper for src and dst ranges"],"tags":["graalvm","vmaccess","copymemory","bounds","buffer"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}