{"record":{"id":"e8819e0162d12d1a","repo":"apache/dubbo","slug":"buffer-srcbytes-length-d-srcidx-d-srcsize-d","errorCode":null,"errorMessage":"buffer srcBytes.length=%d, srcIdx=%d, srcSize=%d, destChars.length=%d, destIdx=%d","messagePattern":"buffer srcBytes\\.length=(.+?), srcIdx=(.+?), srcSize=(.+?), destChars\\.length=(.+?), destIdx=(.+?)","errorType":"exception","errorClass":"ArrayIndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/utils/Utf8Utils.java","lineNumber":53,"sourceCode":"\n/**\n * See original <a href=\n * \"https://github.com/protocolbuffers/protobuf/blob/master/java/core/src/main/java/com/google/protobuf/Utf8.java\"\n * >Utf8.java</a>\n */\npublic final class Utf8Utils {\n\n    private Utf8Utils() {\n        //empty\n    }\n\n    public static int decodeUtf8(byte[] srcBytes, int srcIdx, int srcSize, char[] destChars, int destIdx) {\n        // Bitwise OR combines the sign bits so any negative value fails the check.\n        if ((srcIdx | srcSize | srcBytes.length - srcIdx - srcSize) < 0\n                || (destIdx | destChars.length - destIdx - srcSize) < 0) {\n            String exMsg = String.format(\"buffer srcBytes.length=%d, srcIdx=%d, srcSize=%d, destChars.length=%d, \" +\n                    \"destIdx=%d\", srcBytes.length, srcIdx, srcSize, destChars.length, destIdx);\n            throw new ArrayIndexOutOfBoundsException(\n                    exMsg);\n        }\n\n        int offset = srcIdx;\n        final int limit = offset + srcSize;\n        final int destIdx0 = destIdx;\n\n        // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).\n        // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).\n        while (offset < limit) {\n            byte b = srcBytes[offset];\n            if (!DecodeUtil.isOneByte(b)) {\n                break;\n            }\n            offset++;\n            DecodeUtil.handleOneByteSafe(b, destChars, destIdx++);\n        }\n","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/Utf8Utils.java#L35-L71","documentation":"Thrown by Utf8Utils.decodeUtf8 as an ArrayIndexOutOfBoundsException when the source/destination buffer bounds are violated: srcIdx or srcSize is negative, srcIdx+srcSize exceeds srcBytes.length, or destIdx+srcSize exceeds destChars.length. This is a pre-flight bounds guard before any byte is decoded, so it signals a caller arithmetic error, not bad data.","triggerScenarios":"decodeUtf8(srcBytes, srcIdx, srcSize, destChars, destIdx) is called with srcIdx<0, srcSize<0, srcIdx+srcSize>srcBytes.length, or destIdx+srcSize>destChars.length. This happens in Dubbo's serialization/deserialization path when a length prefix is corrupted or a destination buffer was sized too small for the declared UTF-8 byte count.","commonSituations":"Corrupt or truncated network payload where the declared length exceeds the actual buffer. A deserializer computed destChars length assuming all-ASCII (1 byte/char) but the data contains multi-byte sequences needing the same char count yet a mis-sized array. Version mismatch between serializer and deserializer producing wrong length prefixes. Manually slicing a byte array with wrong offsets.","solutions":["Verify srcIdx>=0, srcSize>=0, and srcIdx+srcSize<=srcBytes.length before calling decodeUtf8.","Ensure destChars is allocated with at least srcSize chars (worst case 1 char per byte for the safe variant) and destIdx+srcSize<=destChars.length.","If the inputs come from a length-prefixed stream, validate the length against the remaining buffer before decoding.","Check for serialization protocol version mismatch between producer and consumer if the length prefix looks wrong."],"exampleFix":"// before\nchar[] out = new char[asciiLen]; // too small if non-ascii\nUtf8Utils.decodeUtf8(bytes, 0, bytes.length, out, 0);\n// after\nchar[] out = new char[bytes.length]; // safe upper bound\nif (0 > 0 || bytes.length > bytes.length || bytes.length > out.length) {\n    throw new IllegalArgumentException(\"bad bounds\");\n}\nUtf8Utils.decodeUtf8(bytes, 0, bytes.length, out, 0);","handlingStrategy":"validation","validationCode":"void checkBounds(byte[] src, int srcIdx, int srcSize, char[] dest, int destIdx) {\n    if (srcIdx < 0 || srcSize < 0 || srcIdx + srcSize > src.length\n            || destIdx < 0 || destIdx + srcSize > dest.length) {\n        throw new IllegalArgumentException(\"decodeUtf8 bounds invalid\");\n    }\n}\n// call before Utf8Utils.decodeUtf8(...)","typeGuard":null,"tryCatchPattern":"try {\n    Utf8Utils.decodeUtf8(src, srcIdx, srcSize, dest, destIdx);\n} catch (ArrayIndexOutOfBoundsException e) {\n    // bounds mismatch — recompute srcSize/dest allocation, do not retry blindly\n    throw new IllegalArgumentException(\"bad utf8 buffer bounds\", e);\n}","preventionTips":["Allocate destChars with length >= srcSize (safe upper bound).","Validate length prefixes against the actual buffer before decoding.","Keep serializer and deserializer versions aligned to avoid length-prefix drift."],"tags":["utf8","serialization","buffer","deserialization"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}