{"record":{"id":"b276666bd8f165e0","repo":"Tencent/tinker","slug":"bad-second-byte","errorCode":null,"errorMessage":"bad second byte","messagePattern":"bad second 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":47,"sourceCode":"\n    /**\n     * Decodes bytes from {@code in} into {@code out} until a delimiter 0x00 is\n     * encountered. Returns a new string containing the decoded characters.\n     */\n    public static String decode(ByteInput in, char[] out) throws UTFDataFormatException {\n        int s = 0;\n        while (true) {\n            char a = (char) (in.readByte() & 0xff);\n            if (a == 0) {\n                return new String(out, 0, s);\n            }\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     */","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/aosp-dexutils/src/main/java/com/tencent/tinker/android/dex/Mutf8.java#L29-L65","documentation":"Thrown by Mutf8.decode when decoding a 2-byte MUTF-8 sequence whose second byte is not a 0b10xxxxxx continuation. In MUTF-8 (dex string encoding), bytes 0xC0–0xDF lead a 2-byte char and the next byte must be 0x80–0xBF; anything else is malformed.","triggerScenarios":"Decoding a dex string_id's MUTF-8 data where a 2-byte sequence's continuation byte was corrupted, or where the string bytes were written by a buggy encoder (or a buffer read started one byte into a multi-byte char).","commonSituations":"Corrupted dex string data from bad patching or partial writes; third-party string obfuscation/encryption tools that mangle MUTF-8; reading a dex buffer with the wrong offset into string_data_item.","solutions":["Validate the dex header checksum/signature; if it fails, the string data is corrupt — obtain a clean copy.","If you produce the dex with custom tooling, encode strings with Mutf8.encode (or a spec-conformant encoder) rather than java.lang.String.getBytes(UTF-8).","Cross-check with baksmali — if baksmali decodes fine, your reader's offset is wrong, not the data."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { String s = Mutf8.decode(in, utf16Len); } catch (UTFDataFormatException e) { mark dex as unusable and fall back to a placeholder string with its id logged; never continue parsing mid-string }","preventionTips":["Treat any MUTF-8 failure as a signal the whole string section is suspect; revalidate the file instead of skipping one string.","Produce dexes only with spec-conformant encoders (Mutf8.encode, d8)."],"tags":["dex","mutf8","string-decoding","parsing","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}