{"record":{"id":"a5b1249e982102c3","repo":"oracle/graal","slug":"arrayoffset-is-less-than-baseoffset","errorCode":null,"errorMessage":"arrayOffset is less than baseOffset","messagePattern":"arrayOffset is less than baseOffset","errorType":"exception","errorClass":"ArrayIndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java","lineNumber":572,"sourceCode":"\n    /**\n     * Checks if a memory access in a guest array is within bounds.\n     *\n     * @param o guest array object\n     * @param offset raw byte offset into array\n     * @param accessSize number of bytes to be accessed\n     * @param language the EspressoLanguage instance\n     * @throws IllegalArrayAccessException if the access is out of bounds\n     */\n    private static void boundsCheck(\n                    @JavaType(Object.class) StaticObject o, long offset, long accessSize, EspressoLanguage language) throws IllegalArrayAccessException {\n        // offset = baseOffset + index * indexScale\n        assert o.getKlass().isArray();\n        Klass klass = o.getKlass();\n        int baseOffset = arrayBaseOffset(klass);\n        int indexScale = arrayIndexScale(klass);\n        if (offset < baseOffset) {\n            throw new IllegalArrayAccessException(\"arrayOffset is less than baseOffset\");\n        }\n        /*\n         * Ensure memory is aligned for operations like sub-word CAS that may temporarily access\n         * memory just beyond array bounds.\n         */\n        int maxIndex = alignUpToIntBytes(baseOffset + o.length(language) * indexScale);\n        if (offset > maxIndex - accessSize) {\n            throw new IllegalArrayAccessException(\"arrayOffset is beyond array length\");\n        }\n    }\n\n    /**\n     * Thrown when {@link #boundsCheck} fails due to an out-of-bounds access.\n     */\n    private static class IllegalArrayAccessException extends Exception {\n        @Serial private static final long serialVersionUID = 1L;\n\n        IllegalArrayAccessException(String msg) {","sourceCodeStart":554,"sourceCodeEnd":590,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/Target_sun_misc_Unsafe.java#L554-L590","documentation":"In the sun.misc.Unsafe substitution, boundsCheck validates a raw byte offset against an array's layout: offset = baseOffset + index * indexScale. If offset < arrayBaseOffset(klass), the computed index would be negative, and IllegalArrayAccessException('arrayOffset is less than baseOffset') is thrown instead of reading out of bounds.","triggerScenarios":"Guest code calling Unsafe.getXxx/putXxx/compareAndSwap on an array with an offset below the array's base offset (e.g. offset 0 or a value computed for a different element type), or misuse of Unsafe.arrayIndexScale math.","commonSituations":"Libraries using sun.misc.Unsafe with hand-computed offsets (off-heap style code pointed at Java arrays); offsets obtained from one array type applied to another; deliberately hostile/probing code.","solutions":["Recompute offsets with Unsafe.arrayBaseOffset(clazz) + index * Unsafe.arrayIndexScale(clazz) for the exact array class.","Prefer VarHandle or java.nio buffers over raw Unsafe offsets.","If a third-party library triggers it, check for an updated version compatible with Espresso's Unsafe semantics."],"exampleFix":"// before\nlong offset = 8L * i; // hardcoded, below baseOffset\nunsafe.getLong(arr, offset);\n\n// after\nlong offset = ((long) unsafe.arrayBaseOffset(long[].class)) + i * unsafe.arrayIndexScale(long[].class);\nunsafe.getLong(arr, offset);","handlingStrategy":"validation","validationCode":"long base = unsafe.arrayBaseOffset(arr.getClass());\nlong scale = unsafe.arrayIndexScale(arr.getClass());\nif (offset < base) throw new IllegalArgumentException(\"offset below base\"); // fail before Unsafe call","typeGuard":null,"tryCatchPattern":"try {\n    value = unsafe.getLong(arr, offset);\n} catch (Exception e) { // IllegalArrayAccessException surfaces as guest AIOOBE-equivalent\n    // recompute offset with arrayBaseOffset/arrayIndexScale\n}","preventionTips":["Always derive offsets from arrayBaseOffset/arrayIndexScale of the exact array class.","Prefer VarHandles or arraycopy over hand-rolled Unsafe math."],"tags":["espresso","unsafe","bounds-check","arrays"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}