{"record":{"id":"4ac4eefb64b214f5","repo":"oracle/graal","slug":"update-spans-the-word-not-supported","errorCode":null,"errorMessage":"Update spans the word, not supported","messagePattern":"Update spans the word, not supported","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/UnsafeSupport.java","lineNumber":98,"sourceCode":"        if (nativeMemory != null && o == null) {\n            return nativeMemory.getInt(offset, MemoryAccessMode.VOLATILE);\n        }\n        return UNSAFE.getIntVolatile(o, offset);\n    }\n\n    private static boolean doCAS(Object o, long offset, int expected, int value, NativeMemory nativeMemory) throws IllegalMemoryAccessException {\n        if (nativeMemory != null && o == null) {\n            return nativeMemory.compareAndExchangeInt(offset, expected, value) == expected;\n        }\n        return UNSAFE.compareAndSwapInt(o, offset, expected, value);\n    }\n\n    static short compareAndExchangeShort(\n                    Object o, long offset,\n                    short expected,\n                    short x, NativeMemory nativeMemory) throws IllegalMemoryAccessException {\n        if ((offset & 3) == 3) {\n            throw new IllegalArgumentException(\"Update spans the word, not supported\");\n        }\n        long wordOffset = offset & ~3;\n        int shift = (int) (offset & 3) << 3;\n        if (isBigEndian()) {\n            shift = 16 - shift;\n        }\n        int mask = 0xFFFF << shift;\n        int maskedExpected = (expected & 0xFFFF) << shift;\n        int maskedX = (x & 0xFFFF) << shift;\n        int fullWord;\n        do {\n            fullWord = doGetIntVolatile(o, wordOffset, nativeMemory);\n            if ((fullWord & mask) != maskedExpected) {\n                return (short) ((fullWord & mask) >> shift);\n            }\n        } while (!doCAS(o, wordOffset,\n                        fullWord, (fullWord & ~mask) | maskedX, nativeMemory));\n        return expected;","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/standard/UnsafeSupport.java#L80-L116","documentation":"UnsafeSupport implements sub-word CAS (compareAndExchangeShort) by read-modify-write of the enclosing 4-byte word. A short aligned such that it straddles a word boundary (offset & 3 == 3) cannot be updated atomically within one int word, so it rejects the request with IllegalArgumentException rather than silently breaking atomicity.","triggerScenarios":"Guest code calling Unsafe.compareAndExchangeShort/compareAndSetShort at a byte offset congruent to 3 mod 4 on a byte[] or object (unaligned short field packing, protocol buffer decode buffers, off-heap struct emulation inside Java arrays).","commonSituations":"Performance libraries packing structs into byte[] and CAS-ing 16-bit fields at odd offsets; data-format parsers that assume host-level atomicity guarantees; code tested only on little-endian hardware where offsets happened to align.","solutions":["Align the 16-bit field to a 2-byte boundary that does not straddle an int word (avoid offset % 4 == 3).","Do a non-atomic read-modify-write under an external lock if straddling is unavoidable.","Use compareAndExchangeInt over the containing word with manual masking instead of the short variant."],"exampleFix":"// before\nshort v = unsafe.compareAndExchangeShort(buf, 7, exp, upd); // 7 % 4 == 3 -> throws\n\n// after\nint wordOff = 7 & ~3;\nint shift = (7 & 3) * 8;\nint mask = 0xFFFF << shift;\n// CAS the containing int word with masked expected/new values","handlingStrategy":"validation","validationCode":"if ((offset & 3) == 3) {\n    // realign field or use int-word CAS with masking\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Layout packed structs so 16-bit fields never sit at offsets ≡ 3 (mod 4).","Test CAS code on both endiannesses and at odd offsets."],"tags":["espresso","unsafe","atomics","alignment"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}