Skip to content

[Bug] inspect-native-initializers can't read either arm64 slice of a universal Mach-O that holds both arm64 and arm64e #9792

Description

@chordpli

Before submitting

Area

Native analysis or decompilation

Observed behavior

Some stock macOS binaries ship three slices: x86_64, arm64 and arm64e. On these files, inspect-native-initializers has no input that reaches either arm64 slice:

  • With no --architecture, it asks the caller to pick one.
  • With --architecture arm64, it says the file "holds several arm64 slices" and selects none.
  • --architecture arm64e isn't an accepted value (the option takes x86|x86_64|arm|arm64), so it fails argument validation.

Only x86_64 works. Following the error's own guidance leads to another refusal, so a caller can't recover.

inspect-macho on the same file picks the arm64 slice and succeeds, so the two tools disagree on how to select a slice from one file.

Reproduction

Built CLI from main at 55b6d2ca2, macOS 26.5.2 on arm64:

$ lipo -detailed_info /usr/bin/file
architecture x86_64   cpusubtype CPU_SUBTYPE_X86_64_ALL  offset 16384
architecture arm64    cpusubtype CPU_SUBTYPE_ARM64_ALL   offset 180224
architecture arm64e   cpusubtype CPU_SUBTYPE_ARM64E      offset 360448

$ rea inspect-native-initializers /usr/bin/file --format json
{"code":"invalid_request","issues":[{"path":["architecture"],"reason":"invalid_value","message":"Universal Mach-O holds x86_64 (subtype 0x3), arm64 (subtype 0x0), arm64 (subtype 0x80000002); select one architecture."}]}

$ rea inspect-native-initializers /usr/bin/file --architecture arm64 --format json
{"code":"invalid_request","issues":[{"path":["architecture"],"reason":"invalid_value","message":"Universal Mach-O holds several arm64 slices (x86_64 (subtype 0x3), arm64 (subtype 0x0), arm64 (subtype 0x80000002)); no slice was selected."}]}

$ rea inspect-native-initializers /usr/bin/file --architecture arm64e --format json
{"code":"VALIDATION_ERROR","message":"REA could not read the command arguments. Check the named argument and its expected type, then try again."}

$ rea inspect-native-initializers /usr/bin/file --architecture x86_64 --format json
ok: slice {"file_offset":16384,"cpu_subtype":3,"architecture":"x86_64"}, coverage complete

$ rea inspect-macho /usr/bin/file --format json   # normalized_result.selected_architecture
{"name":"arm64","container_file_offset":180224}

/usr/bin/ktrace, /usr/bin/trace and /usr/bin/stz on the same host have the same three slices and give the same --architecture arm64 refusal. Two-slice files are fine: /bin/ls and TextEdit (x86_64 + arm64e) and ShortcutDroplet (x86_64 + arm64) each resolve --architecture arm64 to their single arm64 slice.

/usr/bin/file sha256: a4ba66d26a9cfdc70637c78cdacef920f94147f6aa45ccc73858e493589ef94d

Expected behavior

--architecture arm64 should resolve to exactly one slice, the same one other REA tools pick for the same file. inspect_macho already does this through the shared preference order in src/native/MachoArchitectureSelection.ts (arm64, then arm64e, then arm64v8), which would select the arm64 slice at offset 180224 here. The selected slice's cpu_subtype is already reported in the result, so the choice stays visible.

Open question for maintainers: should the arm64e slice of such a file also be selectable on its own? Today no tool input reaches it. That would need a new or extended selector value, so I'd rather leave it out of a fix unless you want it.

Impact and scope

  • Observed: inspect-native-initializers on stock macOS universal binaries that carry both arm64 and arm64e.
  • Source-derived, not run: inspect-go-binary and inspect-rust-binary go through the same selectNativeImage, so a Go or Rust universal binary with both slices should fail the same way. I don't have such a binary to confirm it.

REA version

6.8.0 sources at main (55b6d2ca2)

Runtime and platform

macOS 26.5.2 arm64, Node 24.22.1

Target and artifact context

Stock macOS universal Mach-O executables with x86_64 + arm64 + arm64e slices (/usr/bin/file, /usr/bin/ktrace, /usr/bin/trace, /usr/bin/stz)

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

See Reproduction.

Typed outcome or recovery expected

A successful result for the preferred arm64 slice. If a selection really is ambiguous, the invalid_request should name a selector value that works, not one that leads to another refusal.

Analysis or suspected cause

Source-derived: selectNativeImage in src/native/metadata/MachoSliceSelection.ts matches slices by CPU type only and refuses when more than one slice matches. It doesn't use MACHO_ARCHITECTURE_POLICIES / machoSubtypeRank from src/native/MachoArchitectureSelection.ts, which inspect_macho (via #2040) uses to choose one slice when several share a CPU type.

Additional context

None.

Activity

  1. chordpli commented on Nov 10, 2026

    @chordpli
    ContributorAuthor

    I'm picking this up and will open a PR shortly. The plan is to have selectNativeImage reuse the shared slice preference from MachoArchitectureSelection.ts, so --architecture arm64 picks the same slice inspect_macho does. Selecting the arm64e slice on its own stays out of scope unless you'd like it included. I'll attach before/after runs against /usr/bin/file on the PR.

  2. chordpli commented on Nov 10, 2026

    @chordpli
    ContributorAuthor

    Opened #9793.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions