shwenzhang/AndResGuard · error · AndrolibException

writeSpecNameStringBlock

Error message

writeSpecNameStringBlock %s UTF-16LE length is different name %d, tempByte %d

What it means

The UTF-16LE branch of writeSpecNameStringBlock writes name.length() as the character count, then verifies that the actual UTF-16LE encoding uses exactly length*2 bytes. This fails when the name contains surrogate pairs (emoji, rare CJK), where Java's String.length() counts each surrogate separately but the UTF-16LE byte length still matches length*2 — or when the pool's declared encoding disagrees with the actual content, surfacing an encoding inconsistency.

Solutions

  1. Rename resources containing emoji/supplementary characters to plain ASCII identifiers.
  2. Enable resource name obfuscation so original names never reach this writer.
  3. Patch the check to count code points instead of chars when validating lengths.
  4. Inspect the name printed in the message and fix it in the res source files.
Defensive patterns

Strategy: validation

Validate before calling

static boolean hasSupplementaryChars(String name) {
  return name.codePoints().anyMatch(cp -> cp > 0xFFFF);
}
// reject or rename resources where hasSupplementaryChars(resName) is true

Try / catch

try { ... } catch (AndrolibException e) { if (e.getMessage().contains("UTF-16LE length is different")) { /* surface the resource name from the message; block release until renamed */ } else throw e; }

Prevention

When it happens

Trigger: writeSpecNameStringBlock with isUTF8 == false and a resource name where name.getBytes(UTF_16LE).length != name.length()*2, typically due to surrogate-pair characters combined with the length-field encoding assumptions, or names longer than Short.MAX_VALUE.

Common situations: Resource names containing emoji or supplementary-plane characters; non-ASCII resource identifiers in apps localized with unusual names.

Related errors


AI-assisted analysis of shwenzhang/AndResGuard@e4df245d82 (2026-09-12). Data as JSON: /api/errors/0a0abe421039d5eb. Report an issue: GitHub.

Appendix: source

Thrown at AndResGuard-core/src/main/java/com/tencent/mm/androlib/res/decoder/StringBlock.java:178

        if (name.length() != tempByte.length) {
          throw new AndrolibException(String.format(
              "writeSpecNameStringBlock %s UTF-8 length is different name %d, tempByte %d\n",
              name,
              name.length(),
              tempByte.length
          ));
        }
        System.arraycopy(tempByte, 0, stringBytes, offset, tempByte.length);
        offset += name.length();
        stringBytes[offset++] = NULL;
        totalSize += name.length() + 1;
      } else {
        writeShort(stringBytes, offset, (short) name.length());
        offset += 2;
        totalSize += 2;
        byte[] tempByte = name.getBytes(Charset.forName("UTF-16LE"));
        if ((name.length() * 2) != tempByte.length) {
          throw new AndrolibException(String.format(
              "writeSpecNameStringBlock %s UTF-16LE length is different name %d, tempByte %d\n",
              name,
              name.length(),
              tempByte.length
          ));
        }
        System.arraycopy(tempByte, 0, stringBytes, offset, tempByte.length);
        offset += tempByte.length;
        stringBytes[offset++] = NULL;
        stringBytes[offset++] = NULL;
        totalSize += tempByte.length + 2;
      }
      i++;
    }
    //要保证string size 是4的倍数,要补零
    size = totalSize - stringsOffset;
    if ((size % 4) != 0) {
      int add = 4 - (size % 4);

View on GitHub (pinned to e4df245d82)