Tencent/tinker · error · IOException
Unexpected elf class: {}
Error message
Unexpected elf class: {} What it means
While reading the remainder of the ELF header, ShareElfFile switches on e_ident[EI_CLASS] to read e_entry/e_phoff/e_shoff with the right widths (int for 32-bit, long for 64-bit). Any value other than ELFCLASS32(1) or ELFCLASS64(2) reaches the default branch and throws IOException('Unexpected elf class:'). Although ElfHeader.assertInRange normally rejects bad classes earlier, this branch covers arithmetic-injected or mutated class bytes and defends the width-sensitive reads.
Source
Thrown at tinker-android/tinker-android-loader-no-op/src/main/java/com/tencent/tinker/loader/shareutil/ShareElfFile.java:241
eType = restBuffer.getShort();
eMachine = restBuffer.getShort();
eVersion = restBuffer.getInt();
assertInRange(eVersion, EV_CURRENT, EV_CURRENT, "bad elf version: " + eVersion);
switch (eIndent[EI_CLASS]) {
case ELFCLASS32:
eEntry = restBuffer.getInt();
ePhOff = restBuffer.getInt();
eShOff = restBuffer.getInt();
break;
case ELFCLASS64:
eEntry = restBuffer.getLong();
ePhOff = restBuffer.getLong();
eShOff = restBuffer.getLong();
break;
default:
throw new IOException("Unexpected elf class: " + eIndent[EI_CLASS]);
}
eFlags = restBuffer.getInt();
eEhSize = restBuffer.getShort();
ePhEntSize = restBuffer.getShort();
ePhNum = restBuffer.getShort();
eShEntSize = restBuffer.getShort();
eShNum = restBuffer.getShort();
eShStrNdx = restBuffer.getShort();
}
}
public static class ProgramHeader {
// Segment types.
public static final int PT_NULL = 0;
public static final int PT_LOAD = 1;
public static final int PT_DYNAMIC = 2;
public static final int PT_INTERP = 3;
public static final int PT_NOTE = 4;View on GitHub (pinned to 1b7ea02c23)
Solutions
- Treat the file as corrupt: cleanPatch() and re-apply a verified patch.
- Add md5 verification of patch contents before load so corrupted .so files are rejected before ELF parsing.
- Re-download the patch from the server instead of reusing a locally corrupted copy.
Defensive patterns
Strategy: try-catch
Validate before calling
int elfClass = eIndent[ShareElfFile.ElfHeader.EI_CLASS] & 0xff;
if (elfClass != ShareElfFile.ElfHeader.ELFCLASS32
&& elfClass != ShareElfFile.ElfHeader.ELFCLASS64) {
throw new IOException("invalid elf class byte: " + elfClass);
} Try / catch
catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("elf class")) {
// corrupt ELF: re-fetch the file
}
} Prevention
- Verify checksums of patched native libs before load
- Treat unexpected ELF class as corruption, never as retryable
When it happens
Trigger: Parsing a file whose ELF magic is valid but whose EI_CLASS byte at offset 4 is neither 1 nor 2 — e.g. corrupted ELF, fuzzed/mutated binaries, or files crafted with invalid class identifiers.
Common situations: Bit-rot or partial overwrites of .so files on disk; transferring patches through channels that corrupt binary data; security research/fuzzing inputs fed to ShareElfFile.
Related errors
- bad elf magic: %x %x %x %x.
- bad elf magic: %x %x %x %x.
- Rest bytes insufficient, expect to read {} bytes but only {}
- Unable to find .rodata section.
- {} Rest bytes insufficient, expect to read {} bytes but only
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/7c0353bc7386918c.
Report an issue: GitHub.