{"record":{"id":"d8200152ad73063f","repo":"Tencent/tinker","slug":"bad-byte","errorCode":null,"errorMessage":"bad byte","messagePattern":"bad byte","errorType":"exception","errorClass":"UTFDataFormatException","httpStatus":null,"severity":"error","filePath":"third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Mutf8.java","lineNumber":58,"sourceCode":"            }\n            out[s] = a;\n            if (a < '\\u0080') {\n                s++;\n            } else if ((a & 0xe0) == 0xc0) {\n                int b = in.readByte() & 0xff;\n                if ((b & 0xC0) != 0x80) {\n                    throw new UTFDataFormatException(\"bad second byte\");\n                }\n                out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F));\n            } else if ((a & 0xf0) == 0xe0) {\n                int b = in.readByte() & 0xff;\n                int c = in.readByte() & 0xff;\n                if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {\n                    throw new UTFDataFormatException(\"bad second or third byte\");\n                }\n                out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));\n            } else {\n                throw new UTFDataFormatException(\"bad byte\");\n            }\n        }\n    }\n\n    /**\n     * Returns the number of bytes the modified UTF8 representation of 's' would take.\n     */\n    public static long countBytes(String s, boolean shortLength) throws UTFDataFormatException {\n        long result = 0;\n        final int length = s.length();\n        for (int i = 0; i < length; ++i) {\n            char ch = s.charAt(i);\n            if (ch != 0 && ch <= 127) { // U+0000 uses two bytes.\n                ++result;\n            } else if (ch <= 2047) {\n                result += 2;\n            } else {\n                result += 3;","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Mutf8.java#L40-L76","documentation":"Thrown by Mutf8.decode when the lead byte of a character is not < 0x80, not 0b110xxxxx, and not 0b1110xxxx — i.e. a bare continuation byte (0x80–0xBF) or an invalid 0xF0–0xFF byte where a lead byte was expected. MUTF-8 allows only 1-, 2-, and 3-byte forms.","triggerScenarios":"The decode position lands mid-character (previous sequence consumed the wrong number of bytes), or the data contains raw 4-byte UTF-8 (standard Java UTF-8, not MUTF-8) or binary garbage in the string region.","commonSituations":"Strings written with standard UTF-8 (4-byte surrogates for supplementary chars) instead of MUTF-8's CESU-8-style surrogate pairs; buffer underflow reading past the string's declared length into unrelated bytes.","solutions":["If you generate the dex, ensure supplementary characters (emoji, rare CJK) are written as surrogate pairs via Mutf8.encode, not as 4-byte UTF-8.","Re-align: recompute the string_data_item offset from the string_ids table before decoding.","If a length prefix (utf16_size) mismatch is possible, decode with an explicit length bound rather than until NUL."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch (UTFDataFormatException e) -> quarantine the dex, log first 16 bytes at the failing offset for triage","preventionTips":["If embedding unicode-heavy constants, verify the toolchain emits surrogate pairs (CESU-8 style), not 4-byte UTF-8.","Unit-test your dex generation with supplementary-plane characters (emoji) to catch encoding path mismatches early."],"tags":["dex","mutf8","string-decoding","parsing","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}