{"record":{"id":"eec3c5b5316229f9","repo":"shwenzhang/AndResGuard","slug":"string-data-size-is-not-multiple-of-4-size","errorCode":null,"errorMessage":"String data size is not multiple of 4 (${size}).","messagePattern":"String data size is not multiple of 4 \\((.+?)\\)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/StringBlock.java","lineNumber":90,"sourceCode":"    int styleCount = reader.readInt();\n    int flags = reader.readInt();\n    int stringsOffset = reader.readInt();\n    int stylesOffset = reader.readInt();\n\n    StringBlock block = new StringBlock();\n    block.m_isUTF8 = (flags & UTF8_FLAG) != 0;\n    block.m_stringOffsets = reader.readIntArray(stringCount);\n    block.m_stringOwns = new int[stringCount];\n    Arrays.fill(block.m_stringOwns, -1);\n\n    if (styleCount != 0) {\n      block.m_styleOffsets = reader.readIntArray(styleCount);\n    }\n    {\n      int size = ((stylesOffset == 0) ? chunkSize : stylesOffset) - stringsOffset;\n\n      if ((size % 4) != 0) {\n        throw new IOException(\"String data size is not multiple of 4 (\" + size + \").\");\n      }\n      block.m_strings = new byte[size];\n\n      reader.readFully(block.m_strings);\n    }\n    if (stylesOffset != 0) {\n      int size = (chunkSize - stylesOffset);\n      if ((size % 4) != 0) {\n        throw new IOException(\"Style data size is not multiple of 4 (\" + size + \").\");\n      }\n      block.m_styles = reader.readIntArray(size / 4);\n    }\n    return block;\n  }\n\n  public static int writeSpecNameStringBlock(\n          ExtDataInput reader, ExtDataOutput out, Map<String, Set<String>> specNames, Map<String, Integer> curSpecNameToPos)\n      throws IOException, AndrolibException {","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/shwenzhang/AndResGuard/blob/e4df245d82f27d9a2d0dd108260a3510cbaba849/AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/StringBlock.java#L72-L108","documentation":"StringBlock.read parses the string-pool chunk of resources.arsc (or an XML block). The size of the raw string data region is computed as (stylesOffset or chunkSize) minus stringsOffset, and the arsc format requires this region to be 4-byte aligned. If it isn't, the chunk offsets are inconsistent with the format and the block cannot be read, so an IOException is thrown.","triggerScenarios":"Reading a string pool where (stylesOffset == 0 ? chunkSize : stylesOffset) - stringsOffset is not a multiple of 4 — i.e. malformed offsets in the string pool header, a corrupted chunk, or reading the wrong bytes as a string pool.","commonSituations":"Corrupted resources.arsc or binary XML, APKs rewritten by tools that misalign string pools, or a decoder misreading a chunk boundary due to earlier parse errors.","solutions":["Rebuild the APK with standard aapt/aapt2 so the string pool is correctly aligned, then retry","Validate the input APK (aapt dump resources / badging) and use a clean, unmodified artifact","Do not run other repacking/optimization tools on the APK before AndResGuard","Update AndResGuard; check the exact size value in the message to identify the misaligned chunk"],"exampleFix":"// before: apk repacked by a zip-align-less tool\nAndResGuard.process(repackedApk)\n// after: rebuild and align\n// zipalign -p -f 4 app-unsigned.apk app-aligned.apk\nAndResGuard.process(alignedOriginalApk)","handlingStrategy":"validation","validationCode":"// verify the string pool chunk is well-formed before parsing\nint stringsOffset = header.stringsOffset;\nint endOffset = (header.stylesOffset == 0) ? header.chunkSize : header.stylesOffset;\nif ((endOffset - stringsOffset) % 4 != 0) {\n  throw new IllegalArgumentException(\"Misaligned string pool in resources.arsc — rebuild the apk with aapt2\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  StringBlock.read(reader);\n} catch (IOException e) {\n  if (e.getMessage().contains(\"not multiple of 4\")) {\n    throw new BuildException(\"String pool misaligned; the arsc was likely rewritten by a non-standard tool\", e);\n  }\n  throw e;\n}","preventionTips":["Run zipalign (4-byte) on APKs before/after any repacking","Avoid third-party tools that rewrite arsc string pools","Validate with aapt dump resources before obfuscation","Rebuild from source rather than patching binary arsc files"],"tags":["android","arsc","string-pool","alignment"],"backgroundTag":"invalid-argument-format","analyzedSha":"e4df245d82f27d9a2d0dd108260a3510cbaba849","analyzedAt":"2026-09-12T17:49:07.798Z","contentChangedAt":"2026-09-12T17:49:07.798Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}