{"record":{"id":"b1b8e430f567f240","repo":"skylot/jadx","slug":"reading-after-chunk-end","errorCode":null,"errorMessage":"reading after chunk end","messagePattern":"reading after chunk end","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"jadx-core/src/main/java/jadx/core/xmlgen/ResTableBinaryParser.java","lineNumber":236,"sourceCode":"\t\t\tint entryFlag = is.readInt32();\n\t\t}\n\t\tif (is.getPos() != expectedEndPos) {\n\t\t\tthrow new IOException(String.format(\"Error reading type spec chunk at offset 0x%x\", chunkStart));\n\t\t}\n\t}\n\n\tprivate void parseLibraryTypeChunk(long chunkStart) throws IOException {\n\t\tLOG.trace(\"parsing library type chunk starting at offset {}\", chunkStart);\n\t\tis.checkInt16(12, \"Unexpected header size\");\n\t\tint chunkSize = is.readInt32();\n\t\tlong expectedEndPos = chunkStart + chunkSize;\n\t\tint count = is.readInt32();\n\t\tfor (int i = 0; i < count; i++) {\n\t\t\tint packageId = is.readInt32();\n\t\t\tString packageName = is.readString16Fixed(128);\n\t\t\tLOG.info(\"Found resource shared library {}, pkgId: {}\", packageName, packageId);\n\t\t\tif (is.getPos() > expectedEndPos) {\n\t\t\t\tthrow new IOException(\"reading after chunk end\");\n\t\t\t}\n\t\t}\n\t\tif (is.getPos() != expectedEndPos) {\n\t\t\tthrow new IOException(String.format(\"Error reading library chunk at offset 0x%x\", chunkStart));\n\t\t}\n\t}\n\n\t/**\n\t * Parse an <code>ResTable_type</code> (except for the 2 bytes <code>uint16_t</code>\n\t * from <code>ResChunk_header</code>).\n\t *\n\t * @see <a href=\n\t *      \"https://github.com/aosp-mirror/platform_frameworks_base/blob/master/libs/androidfw/include/androidfw/ResourceTypes.h\"></a>ResourceTypes.h</a>\n\t */\n\tprivate void parseTypeChunk(long start, PackageChunk pkg) throws IOException {\n\t\t/* int headerSize = */\n\t\tis.readInt16();\n\t\t/* int size = */","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/skylot/jadx/blob/e738a26571d02919f01df40de93bc9a44dee4e18/jadx-core/src/main/java/jadx/core/xmlgen/ResTableBinaryParser.java#L218-L254","documentation":"While iterating library entries inside a RES_TABLE_TYPE_LIBRARY chunk, the parser checks after each entry that the stream position has not exceeded the declared chunk end. If getPos() > expectedEndPos, it means a library entry read past the boundary — the count field claims more entries than the chunk can hold.","triggerScenarios":"parseLibraryTypeChunk loops count times, each iteration reading a 4-byte packageId and a 256-byte (fixed 128 char) package name. After each iteration, if is.getPos() exceeds expectedEndPos (chunkStart + chunkSize), this IOException fires. The fixed 264-byte-per-entry size makes this likely when count is too large for the declared chunkSize.","commonSituations":"Malformed resources.arsc with an inflated library count. Corrupt chunkSize field. APKs using shared library resource references with non-standard encoding.","solutions":["Re-extract the APK from the original source","Upgrade jadx to the latest version","Report the APK to jadx maintainers","Use --no-res to skip resource decoding"],"exampleFix":"// Skip resources:\njadxArgs.setSkipResources(true);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    resTableParser.decode(stream);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"reading after chunk end\")) {\n        LOG.warn(\"Library chunk overflow, skipping resources\", e);\n        jadxArgs.setSkipResources(true);\n    }\n}","preventionTips":["Validate APK integrity before parsing","Use --no-res as a fallback for corrupt resources","Keep jadx updated"],"tags":["android","binary-parsing","validation","resource-table","corrupt-input"],"backgroundTag":null,"analyzedSha":"e738a26571d02919f01df40de93bc9a44dee4e18","analyzedAt":"2026-08-14T00:10:24.238Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}