[GH-ISSUE #8723] [Bug] inspect-macho reports chained imports missing from the undefined symbol table with null names #7524

Open
opened 2026-11-03 05:15:48 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @Lew1sWong on GitHub (Nov 3, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8723

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Native analysis or decompilation

Observed behavior

inspect-macho reports many chained-fixup imports with name: null and name_status: "ambiguous", although dyld_info -imports prints an unambiguous name for each row. It also reports the imports collection with total: null and exhaustive: false.

Counts on macOS 27.0.1 arm64, REA b912ec184:

Target Import rows name: null
/Applications/Keynote.app/Contents/MacOS/Keynote 5,997 1,525
/System/Applications/Music.app/Contents/MacOS/Music 7,906 3,561
Electron Framework (shipped inside an Electron app) 5,081 2,581
a 2-line C++ dylib (below) 1 1

Reproduction

cat > coalesce.cpp <<'CPP'
inline __attribute__((visibility("default"))) int inl(int x) { return x * 3; }
__attribute__((visibility("default"))) int (*getinl())(int) { return &inl; }
CPP
xcrun clang++ -arch arm64 -dynamiclib coalesce.cpp -o libcoalesce.dylib
xcrun dyld_info -imports libcoalesce.dylib
nm -gju --no-dyldinfo libcoalesce.dylib   # undefined names: none
node scripts/rea.mjs inspect-macho libcoalesce.dylib --json

Observed:

-imports:
  0x0000  __Z3inli  (from <weak-def-coalesce>)
{"name":null,"raw_name":"0x0000  __Z3inli  (from <weak-def-coalesce>)","name_status":"ambiguous",...,"source":"<weak-def-coalesce>"}

Expected behavior

name: "__Z3inli", name_status: "exact", which is the name dyld_info prints and the name stored in the binary's chained-fixup import table.

Impact and scope

P2. Import identity is lost for a large share of real Swift and C++ binaries, including Apple apps and Electron. Callers see null names they cannot match against exports, dependencies or other evidence. The regression dates from d27e3f8e8 (2026-10-26).

REA version

6.8.0, source b912ec184

Runtime and platform

Node.js 24.22.1; macOS 27.0.1 (26A434) arm64; Apple clang 21.0.0

Target and artifact context

The 2-line dylib above, plus installed Apple and Electron binaries; no private target data

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

  • For chained binaries, parseDyldImports considers two readings of each row, because the ordinal is followed by one space in Apple's source but two in installed-tool output. Since d27e3f8e8 it keeps a reading only when nm -gju --no-dyldinfo (undefined symbol-table names) lists it.
  • Two groups of imports are never in that list:
    • weak-def-coalesce rows bind defined weak symbols (nm -gjU lists __Z3inli; nm -gju lists nothing);
    • Swift and other images import names with no symbol-table entry at all. For Keynote's arm64 slice, 1,770 import names are absent from both nm -gju and nm -gjU, and llvm-nm's dyld-info pass (nm -gju without --no-dyldinfo, 5.4 s) adds none of them.

Typed outcome or recovery expected

Exact names for rows whose name is in the slice's own chained-fixup import table. An explicit ambiguous result only where the text really cannot be split, such as #6648's addend suffixes.

Analysis or suspected cause

Source-derived: the names dyld_info prints for chained rows are entries of the slice's LC_DYLD_CHAINED_FIXUPS import table, which AppleMachoFixups already decodes. The name inventory used for disambiguation is incomplete, because it comes from nm -gju rather than from that table.

Additional context

I have a fix and regression tests ready and will open a PR.

Originally created by @Lew1sWong on GitHub (Nov 3, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8723 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Native analysis or decompilation ### Observed behavior `inspect-macho` reports many chained-fixup imports with `name: null` and `name_status: "ambiguous"`, although `dyld_info -imports` prints an unambiguous name for each row. It also reports the imports collection with `total: null` and `exhaustive: false`. Counts on macOS 27.0.1 arm64, REA `b912ec184`: | Target | Import rows | `name: null` | |---|---|---| | `/Applications/Keynote.app/Contents/MacOS/Keynote` | 5,997 | 1,525 | | `/System/Applications/Music.app/Contents/MacOS/Music` | 7,906 | 3,561 | | Electron Framework (shipped inside an Electron app) | 5,081 | 2,581 | | a 2-line C++ dylib (below) | 1 | 1 | ### Reproduction ```sh cat > coalesce.cpp <<'CPP' inline __attribute__((visibility("default"))) int inl(int x) { return x * 3; } __attribute__((visibility("default"))) int (*getinl())(int) { return &inl; } CPP xcrun clang++ -arch arm64 -dynamiclib coalesce.cpp -o libcoalesce.dylib xcrun dyld_info -imports libcoalesce.dylib nm -gju --no-dyldinfo libcoalesce.dylib # undefined names: none node scripts/rea.mjs inspect-macho libcoalesce.dylib --json ``` Observed: ```text -imports: 0x0000 __Z3inli (from <weak-def-coalesce>) {"name":null,"raw_name":"0x0000 __Z3inli (from <weak-def-coalesce>)","name_status":"ambiguous",...,"source":"<weak-def-coalesce>"} ``` ### Expected behavior `name: "__Z3inli"`, `name_status: "exact"`, which is the name dyld_info prints and the name stored in the binary's chained-fixup import table. ### Impact and scope P2. Import identity is lost for a large share of real Swift and C++ binaries, including Apple apps and Electron. Callers see `null` names they cannot match against exports, dependencies or other evidence. The regression dates from d27e3f8e8 (2026-10-26). ### REA version 6.8.0, source `b912ec184` ### Runtime and platform Node.js 24.22.1; macOS 27.0.1 (26A434) arm64; Apple clang 21.0.0 ### Target and artifact context The 2-line dylib above, plus installed Apple and Electron binaries; no private target data ### Interface CLI ### Earliest failure stage Transport or result projection ### Relevant output or evidence - For chained binaries, `parseDyldImports` considers two readings of each row, because the ordinal is followed by one space in Apple's source but two in installed-tool output. Since d27e3f8e8 it keeps a reading only when `nm -gju --no-dyldinfo` (undefined symbol-table names) lists it. - Two groups of imports are never in that list: - **weak-def-coalesce rows** bind *defined* weak symbols (`nm -gjU` lists `__Z3inli`; `nm -gju` lists nothing); - **Swift and other images** import names with no symbol-table entry at all. For Keynote's arm64 slice, 1,770 import names are absent from both `nm -gju` and `nm -gjU`, and llvm-nm's dyld-info pass (`nm -gju` without `--no-dyldinfo`, 5.4 s) adds none of them. ### Typed outcome or recovery expected Exact names for rows whose name is in the slice's own chained-fixup import table. An explicit ambiguous result only where the text really cannot be split, such as #6648's addend suffixes. ### Analysis or suspected cause Source-derived: the names dyld_info prints for chained rows are entries of the slice's `LC_DYLD_CHAINED_FIXUPS` import table, which `AppleMachoFixups` already decodes. The name inventory used for disambiguation is incomplete, because it comes from `nm -gju` rather than from that table. ### Additional context I have a fix and regression tests ready and will open a PR.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#7524
No description provided.