Repository navigation
Panic: index out of bounds in ARM arch process_code on ELF with no STT_FUNC symbols in .text #352
Description
Summary
objdiff-cli report generate panics with index out of bounds: the len is 0 but the index is 18446744073709551615 at objdiff-core/src/arch/arm.rs:130:29 when an ARM ELF object has a non-empty .text section but no STT_FUNC symbol covering it — i.e. either zero symbols pointing into the .text section, or only STT_OBJECT/STT_SECTION symbols there.
The 18446744073709551615 is usize::MAX, which suggests a 0_usize - 1 underflow when the code-symbol iteration yields an empty list.
Reproduction
Hit reliably while running objdiff-cli report generate on the Yu-Gi-Oh! GX Spirit Caller decomp project (Nintendo DS, ARM, mwccarm 2.0/sp1p5 toolchain via ds-decomp). Brief 187 ([PR #pending]) ships a workaround filter in the project's own tooling. The relevant tool is objdiff-cli v2.7.1.
Minimal panic command:
RUST_BACKTRACE=1 ./objdiff-cli report generate -p . -o /tmp/r.json -d
(-d forces single-threaded so the panic surfaces deterministically.)
Failure modes that trigger the panic
We bisected to find every crashing unit and grouped them by ELF shape:
-
.textexists with content but no symbol covers it. Example: a delinked TU with.textcarrying real ARM instruction bytes (size 0x86 in our case) but onlySTT_SECTION(type 3) section symbols and external (undefined) function references. NoSTT_FUNCsymbol with non-zerost_sizeandst_shndx == .text. -
.textexists with content but onlySTT_OBJECTsymbols cover it. Example: aBuildInfodata blob the linker placed in.textinstead of.rodata(size 0xcc, singleSTT_OBJECTsymbol). The ARM arch processor tries to disassemble it as code → crashes. -
Empty
.textsection. Often combined with (1) — zero useful symbols.
Backtrace
thread '<unnamed>' panicked at objdiff-core/src/arch/arm.rs:130:29:
index out of bounds: the len is 0 but the index is 18446744073709551615
stack backtrace:
0: _rust_begin_unwind
1: core::panicking::panic_fmt
2: core::panicking::panic_bounds_check
3: <objdiff_core::arch::arm::ObjArchArm as objdiff_core::arch::ObjArch>::process_code
4: objdiff_core::diff::code::process_code_symbol
5: objdiff_core::diff::diff_objs
6: objdiff_cli::cmd::report::report_object
...
Minimal reproducer
Tiny ARM ELF (1020 bytes) that triggers the panic — has .text size 0x86 but only STT_SECTION + external-reference symbols (no STT_FUNC in .text).
Base64-encoded `repro.o`
f0VMRgEBAQAAAAAAAAAAAAEAKAABAAAAAAAAAAAAAADkAgAAAAAAADQAAAAAACgABwAGAP/e/+f/3v/n/97/5//en9uRPDQp6rfavPMZToUu5GvkIJkkiAaBdvlJWIXX5U8uiEcvduaXm2EkY8+44A7gB0JWZ693X7or5yjBkmMf+PkC/TYZvt89ylv7Rc9obFfNWkVPlcq1L+ScC8dR4cF6oLYS9ZGe9a20XMlApUhsM7kufxvm10q+AAAAAAwAAAAYAAAA/////w4AAAD/////DwAAAP////8QAAAA/////wUAAAD/////CAAAAP////8HAAAA/////wkAAAD/////CgAAAP////8LAAAA/////wIAAAD/////EgAAAP////8TAAAA/////xQAAAD/////FQAAAP////8XAAAA/////xkAAAD/////GgAAAP////8lAAAA/////yEAAAD/////HAAAAP////8dAAAA/////x8AAAD/////IAAAAP////8bAAAA/////wQAAAD/////IgAAAP////8jAAAA/////0xDMDgAAAAATEMxMAAAAABMQzEyAAAAAExDMTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwABAAAAAAAAAAAAAAAAAAMAAgAdAAAAAAAAAAAAAAAgAAAAOQAAAAAAAADoAAAAEQACAA8AAADoAAAACAAAABEAAgBHAAAA8AAAAAgAAAARAAIAAQAAAPgAAAAIAAAAEQACACsAAAAAAQAACAAAABEAAgAAZGF0YV8wMjBjM2NiOABkYXRhXzAyMGMzY2E4AGZ1bmNfMDIwMDBjNDQAZGF0YV8wMjBjM2NjMABkYXRhXzAyMGMzYmMwAGRhdGFfMDIwYzNjYjAAAAAAAAAAAAIDAAAAAAAAAC50ZXh0AC5zaHN0cnRhYgAuc3RydGFiAC5zeW10YWIALnJlbGEuZGF0YQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAAGAAAAAAAAADQAAACGAAAAAAAAAAAAAAACAAAAAAAAACYAAAABAAAAAwAAAAAAAAC6AAAACAEAAAAAAAAAAAAAAQAAAAAAAAAhAAAABAAAAEAAAAAAAAAArAIAAAwAAAAEAAAAAgAAAAQAAAAMAAAAGQAAAAIAAAAAAAAAAAAAAMQBAACQAAAABQAAAAQAAAAEAAAAEAAAABEAAAADAAAAAAAAAAAAAABUAgAAVQAAAAAAAAAAAAAAAQAAAAAAAAAHAAAAAwAAAAAAAAAAAAAAuAIAACwAAAAAAAAAAAAAAAEAAAAAAAAA
To repro:
base64 -d > repro.o <<EOF_B64
[paste base64 from above]
EOF_B64
cat > objdiff.json <<EOF_JSON
{
"min_version": "2.0",
"custom_make": "ninja",
"target_dir": "",
"base_dir": "",
"units": [
{"name": "repro", "target_path": "repro.o", "metadata": {}}
]
}
EOF_JSON
objdiff-cli report generate -p . -o /tmp/r.json -d
Expected: report.json generated. Actual: panic at arm.rs:130.
Suggested fix direction
process_code in objdiff-core/src/arch/arm.rs likely iterates over symbols pointing into the code section and then derives a span end via something like symbols[idx + 1].address or symbols.last().address + symbols.last().size — when symbols is empty, the index/range math underflows. Guarding the iteration with if symbols.is_empty() { return Ok(()); } (or equivalent) at the function head should make the panic into a clean no-op for code-less / data-only .text sections.
(Same shape applies whether all symbols are STT_OBJECT or simply absent — happy to test a fix branch against our project's full 3330-unit corpus if helpful.)
Project context
This panic blocks objdiff-verified code-match metrics for the entire decomp — build/<region>/report.json never gets written, so we can't measure function-level matching progress without a workaround. Brief 187 ships a project-local filter (tools/objdiff_filter_panic_units.py) that drops the ~20 affected units before invoking objdiff-cli report generate, but the right fix is upstream.
Filed from the spirit-caller project's brief 187 PR — happy to share more diagnostics or test patches.
Activity
brief 187: code-decomp resumption prep — `ninja report` works + queue…