{"record":{"id":"0f488bf6e8790332","repo":"Tencent/tinker","slug":"bad-isa-num","errorCode":null,"errorMessage":"Bad isa num: {}","messagePattern":"Bad isa num: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"tinker-android/tinker-android-loader-no-op/src/main/java/com/tencent/tinker/loader/shareutil/ShareOatUtil.java","lineNumber":100,"sourceCode":"            try {\n                Integer.parseInt(oatVersion);\n            } catch (NumberFormatException e) {\n                throw new IOException(\"Bad oat version: \" + oatVersion);\n            }\n\n            ByteBuffer buffer = ByteBuffer.allocate(128);\n            buffer.order(elfFile.getDataOrder());\n            // TODO This is a risk point, since each oat version may use a different offset.\n            // So far it's ok. Perhaps we should use oatVersionNum to judge the right offset in\n            // the future.\n            final int isaNumOffsetFromOatBegin = 12;\n            channel.position(roDataHdr.shOffset + isaNumOffsetFromOatBegin);\n            buffer.limit(4);\n            ShareElfFile.readUntilLimit(channel, buffer, \"Failed to read isa num.\");\n\n            int isaNum = buffer.getInt();\n            if (isaNum < 0 || isaNum >= InstructionSet.values().length) {\n                throw new IOException(\"Bad isa num: \" + isaNum);\n            }\n\n            switch (InstructionSet.values()[isaNum]) {\n                case kArm:\n                case kThumb2:\n                    result = \"arm\";\n                    break;\n                case kArm64:\n                    result = \"arm64\";\n                    break;\n                case kX86:\n                    result = \"x86\";\n                    break;\n                case kX86_64:\n                    result = \"x86_64\";\n                    break;\n                case kMips:\n                    result = \"mips\";","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/tinker-android/tinker-android-loader-no-op/src/main/java/com/tencent/tinker/loader/shareutil/ShareOatUtil.java#L82-L118","documentation":"ShareOatUtil reads a 4-byte int at fixed offset 12 from the OAT header (the instruction-set enum index) and requires 0 <= isaNum < InstructionSet.values().length. An out-of-range value means the header layout does not match the expected OAT format (the in-code TODO explicitly flags this fixed offset as a risk across oat versions), so an IOException('Bad isa num') is thrown instead of indexing the enum with garbage.","triggerScenarios":"Parsing an oat file produced by an ART version that places different data at offset 12; a corrupt or truncated odex where the isa field lands on arbitrary bytes; an odex built for an ABI whose enum index is unknown to this tinker version.","commonSituations":"New Android versions changing the OAT header layout after this code shipped; unusual ABIs (mips-era or new ISAs) not present in the embedded InstructionSet enum; vendor-modified ART.","solutions":["Delete the odex and retry patch install so the on-device dex2oat regenerates a matching file.","Fall back to ShareTinkerInternals.getCurrentInstructionSet() (Build.CPU_ABI) when the oat-based parse fails, instead of propagating the error.","Upgrade tinker to a version whose InstructionSet table and offset handling cover the target Android release.","Verify the patch is built for the same ABI as the running process (no 32/64-bit odex mixing)."],"exampleFix":"// before\nint isaNum = buffer.getInt();\nif (isaNum < 0 || isaNum >= InstructionSet.values().length) {\n    throw new IOException(\"Bad isa num: \" + isaNum);\n}\n\n// after\nint isaNum = buffer.getInt();\nif (isaNum < 0 || isaNum >= InstructionSet.values().length) {\n    ShareTinkerLog.w(TAG, \"Bad isa num \" + isaNum + \", fall back to abi-based isa.\");\n    return ShareTinkerInternals.getCurrentInstructionSet();\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { isa = ShareOatUtil.readOatInstructionSet(f); } catch (IOException e) { isa = ShareTinkerInternals.getCurrentInstructionSet(); }","preventionTips":["Fall back to ABI-based instruction-set detection when the oat header cannot be trusted.","Keep tinker updated so the fixed-offset parser matches the oat versions on your device matrix.","Never parse an odex produced for a different Android/ART version."],"tags":["oat","instruction-set","abi","android"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}