Tencent/tinker · error · IOException
Unexpected elf class: {}
Error message
Unexpected elf class: {} What it means
In ShareElfFile.ElfHeader's constructor, after reading e_entry/e_phoff/e_shoff the switch on eIndent[EI_CLASS] falls through to default and throws IOException("Unexpected elf class") for any class byte other than ELFCLASS32/ELFCLASS64. In practice the preceding assertInRange already rejects such values, so this branch is defensive; seeing it means the class byte was mutated between the two reads or assertInRange was bypassed.
Source
Thrown at tinker-android/tinker-android-loader/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 as a corrupted-file signal: pull the file and validate with readelf -h to inspect the class byte.
- Delete the corrupted odex/oat so the system regenerates it, or reinstall the app.
- Wrap ShareElfFile/ShareOatUtil usage in try-catch and skip oat parsing on failure.
- Verify file integrity (length, md5) before parsing.
Defensive patterns
Strategy: try-catch
Validate before calling
int eiClass = readEiClassByte(file); // read e_indent[4] yourself
if (eiClass != 1 && eiClass != 2) {
// reject file before ShareElfFile parses it
} Try / catch
try {
elfFile = new ShareElfFile(file);
} catch (IOException e) {
// covers 'Unexpected elf class' and magic errors: treat file as corrupt, regenerate
} Prevention
- Validate e_indent bytes (magic + class + data encoding) before full parsing.
- Avoid concurrent writes to files being parsed.
- Checksum files before parsing to catch corruption early.
When it happens
Trigger: Parsing an ELF whose EI_CLASS byte is neither 1 (32-bit) nor 2 (64-bit) at the point e_entry/e_phoff/e_shoff are decoded — normally impossible because assertInRange(EI_CLASS, ELFCLASS32, ELFCLASS64, ...) runs first.
Common situations: Corrupted ELF file where header bytes are inconsistent; concurrent modification of the file during parsing; extremely rarely, an OEM odex container with non-standard identification bytes.
Related errors
- Rest bytes insufficient, expect to read {} bytes but only {}
- bad elf magic: %x %x %x %x.
- Unexpected elf class: {}
- 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/3d96cfb2f6e47b0b.
Report an issue: GitHub.