[GH-ISSUE #3389] [Bug] inspect-macho rejects a valid arm64e.x1 FAT slice #1255

Closed
opened 2026-10-16 21:03:26 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 14, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/3389

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

On a macOS arm64 host, inspect-macho fails on a valid universal executable containing x86_64 and arm64e.x1 slices. REA selects the latter slice but invokes a required native command for arm64e, which is absent. The source-built executable below was never run.

The CLI exits with status 1 and returns code: "execution_failure". Its diagnostics identify otool, reason: "nonzero-exit", and exit_code: 1. The captured diagnostic ends with sample-fat does not contain architecture: arm64e. REA returns no Mach-O inspection result, although the direct native-tool command with the exact arm64e.x1 spelling succeeds. The input SHA-256 was unchanged after inspection.

Reproduction

  1. Start from a clean checkout and install its locked dependencies and build its runtime.
git clone https://github.com/morluto/rea.git rea
cd rea
git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063
npm ci
npm run build:cached
  1. From the repository root, create the source and executable outside the checkout, isolate REA's home and temporary directory, and compare the native tool with REA. The installed Apple toolchain must accept arm64e.x1; the environment listed below does.
rea_root="$PWD"
probe_root="$(mktemp -d -t rea-macho-variant)"
cd "$probe_root"
mkdir home tmp
cat > sample.c <<'C'
int exported_value(void) { return 42; }
int main(void) { return exported_value(); }
C
xcrun clang -arch x86_64 -arch arm64e.x1 sample.c -o sample-fat
xcrun lipo -detailed_info sample-fat
xcrun otool -h -l -arch arm64e.x1 sample-fat
env HOME="$PWD/home" TMPDIR="$PWD/tmp" \
  node "$rea_root/scripts/rea.mjs" inspect-macho "$PWD/sample-fat" --json
  1. Observe that lipo lists x86_64 and arm64e.x1, the exact-architecture otool command succeeds, and REA exits 1 with the absent-arm64e diagnostic. The CLI failure, direct native-tool success, and unchanged input were reproduced with this source-built executable.

  2. To use the observed workaround, thin a copy to the selected slice and inspect that copy.

xcrun lipo sample-fat -thin arm64e.x1 -output sample-thin
env HOME="$PWD/home" TMPDIR="$PWD/tmp" \
  node "$rea_root/scripts/rea.mjs" inspect-macho "$PWD/sample-thin" --json

Inspection of sample-thin succeeded. It supplies selected-code analysis under a different artifact identity; inspect the original FAT inventory and container offsets separately.

Expected behavior

Inspection should return the selected arm64e.x1 image and preserve that exact slice identity and its container offset. Commands used to inspect that slice should address an architecture actually present in the input.

docs/native-investigation.md:264-272 states that the normalized image and selected_architecture describe the exact selected lipo slice and its container offset. src/contracts/native/nativeToolContracts.ts:95-96 advertises standalone Mach-O slice inspection.

Impact and scope

  • Impact level: P2.
  • Assessment status: supported.
  • Impact basis: Static Mach-O inspection fails for a valid, bounded slice combination on an admitted host. The failure blocks this operation without modifying the input.
  • Workaround status: available.
  • Workaround basis: xcrun lipo sample-fat -thin arm64e.x1 -output sample-thin followed by inspection of sample-thin succeeded. This supplies analysis of the selected code under a different artifact identity; the original FAT inventory and container offsets must be inspected separately.

REA version

6.4.0 (main at 8dde6370d0)

Runtime and platform

Node v26.10.0, macOS 27.0.1 arm64, Apple clang 21.0.0. The reproduction used the existing built runtime without source changes.

Target and artifact context

A valid source-built universal FAT Mach-O executable named sample-fat, containing x86_64 and arm64e.x1 slices. The executable was inspected statically and never run. The selected slice's native inspection succeeded when addressed with its exact spelling, and REA inspection left the original input SHA-256 unchanged.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The observed CLI exit status was 1. The following excerpt retains the reported error and diagnostic fields and the diagnostic's final text.

code: "execution_failure"
tool: otool
reason: "nonzero-exit"
exit_code: 1
sample-fat does not contain architecture: arm64e
  • Failure source: The executed public CLI reproduction above.
  • Evidence provenance: observed.
  • Local verification: reproduced.
  • Reproduction completeness: complete.

Typed outcome or recovery expected

Run the same universal-file inspection and require success with selected_architecture.name: "arm64e.x1", the matching original-container offset, and selected-slice metadata. Compare with the exact-architecture native-tool output. Keep an ordinary thin Mach-O control working and verify that the original universal input remains unchanged. Selecting an unrelated slice or returning metadata under a shortened architecture name does not restore the exact selected-slice contract.

Analysis or suspected cause

Source-derived reasoning: src/native/NativeMachoInspection.ts:422-434 converts the selected arm64e.x1 name to arm64e for required tools other than dyld_info. The selectedArchitectureArguments helper strips the suffix before constructing those tool arguments. This source reading is consistent with the observed absent-arm64e diagnostic and the successful direct otool -h -l -arch arm64e.x1 command; it does not establish a tested fix.

Additional context

  • Related completed issue #674 reported inspect-macho passing absent arm64 arguments for universal arm64e files and discussed tool-specific ABI spellings; this reproduction exposes a remaining or regressed arm64e.x1 case in which the argument becomes the absent arm64e spelling.
  • Related open issue #3072 concerns Hopper selecting an arm64e.x1 slice whose instructions it cannot decode; this report concerns required native static-inspection commands rejecting an architecture argument absent from the input.
  • Related open issue #3282 requests Ghidra support for importing a selected universal slice; this report concerns inspect-macho, which admits the file and then fails in a required native command.
  • Related completed issues #1168 and #1765 concern variant-name and subtype validation during inspect-artifact; this report concerns native inspection after slice selection rather than FAT-table integrity validation.
Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3389 ### 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 On a macOS arm64 host, `inspect-macho` fails on a valid universal executable containing `x86_64` and `arm64e.x1` slices. REA selects the latter slice but invokes a required native command for `arm64e`, which is absent. The source-built executable below was never run. The CLI exits with status 1 and returns `code: "execution_failure"`. Its diagnostics identify `otool`, `reason: "nonzero-exit"`, and `exit_code: 1`. The captured diagnostic ends with `sample-fat does not contain architecture: arm64e`. REA returns no Mach-O inspection result, although the direct native-tool command with the exact `arm64e.x1` spelling succeeds. The input SHA-256 was unchanged after inspection. ### Reproduction 1. Start from a clean checkout and install its locked dependencies and build its runtime. ```sh git clone https://github.com/morluto/rea.git rea cd rea git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063 npm ci npm run build:cached ``` 2. From the repository root, create the source and executable outside the checkout, isolate REA's home and temporary directory, and compare the native tool with REA. The installed Apple toolchain must accept `arm64e.x1`; the environment listed below does. ```sh rea_root="$PWD" probe_root="$(mktemp -d -t rea-macho-variant)" cd "$probe_root" mkdir home tmp cat > sample.c <<'C' int exported_value(void) { return 42; } int main(void) { return exported_value(); } C xcrun clang -arch x86_64 -arch arm64e.x1 sample.c -o sample-fat xcrun lipo -detailed_info sample-fat xcrun otool -h -l -arch arm64e.x1 sample-fat env HOME="$PWD/home" TMPDIR="$PWD/tmp" \ node "$rea_root/scripts/rea.mjs" inspect-macho "$PWD/sample-fat" --json ``` 3. Observe that `lipo` lists `x86_64` and `arm64e.x1`, the exact-architecture `otool` command succeeds, and REA exits 1 with the absent-`arm64e` diagnostic. The CLI failure, direct native-tool success, and unchanged input were reproduced with this source-built executable. 4. To use the observed workaround, thin a copy to the selected slice and inspect that copy. ```sh xcrun lipo sample-fat -thin arm64e.x1 -output sample-thin env HOME="$PWD/home" TMPDIR="$PWD/tmp" \ node "$rea_root/scripts/rea.mjs" inspect-macho "$PWD/sample-thin" --json ``` Inspection of `sample-thin` succeeded. It supplies selected-code analysis under a different artifact identity; inspect the original FAT inventory and container offsets separately. ### Expected behavior Inspection should return the selected `arm64e.x1` image and preserve that exact slice identity and its container offset. Commands used to inspect that slice should address an architecture actually present in the input. `docs/native-investigation.md:264-272` states that the normalized image and `selected_architecture` describe the exact selected lipo slice and its container offset. `src/contracts/native/nativeToolContracts.ts:95-96` advertises standalone Mach-O slice inspection. ### Impact and scope - Impact level: P2. - Assessment status: supported. - Impact basis: Static Mach-O inspection fails for a valid, bounded slice combination on an admitted host. The failure blocks this operation without modifying the input. - Workaround status: available. - Workaround basis: `xcrun lipo sample-fat -thin arm64e.x1 -output sample-thin` followed by inspection of `sample-thin` succeeded. This supplies analysis of the selected code under a different artifact identity; the original FAT inventory and container offsets must be inspected separately. ### REA version 6.4.0 (main at 8dde6370d0809ad04cda3342d4e6f290f48aa063) ### Runtime and platform Node v26.10.0, macOS 27.0.1 arm64, Apple clang 21.0.0. The reproduction used the existing built runtime without source changes. ### Target and artifact context A valid source-built universal FAT Mach-O executable named `sample-fat`, containing `x86_64` and `arm64e.x1` slices. The executable was inspected statically and never run. The selected slice's native inspection succeeded when addressed with its exact spelling, and REA inspection left the original input SHA-256 unchanged. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The observed CLI exit status was 1. The following excerpt retains the reported error and diagnostic fields and the diagnostic's final text. ```text code: "execution_failure" tool: otool reason: "nonzero-exit" exit_code: 1 sample-fat does not contain architecture: arm64e ``` - Failure source: The executed public CLI reproduction above. - Evidence provenance: observed. - Local verification: reproduced. - Reproduction completeness: complete. ### Typed outcome or recovery expected Run the same universal-file inspection and require success with `selected_architecture.name: "arm64e.x1"`, the matching original-container offset, and selected-slice metadata. Compare with the exact-architecture native-tool output. Keep an ordinary thin Mach-O control working and verify that the original universal input remains unchanged. Selecting an unrelated slice or returning metadata under a shortened architecture name does not restore the exact selected-slice contract. ### Analysis or suspected cause Source-derived reasoning: `src/native/NativeMachoInspection.ts:422-434` converts the selected `arm64e.x1` name to `arm64e` for required tools other than `dyld_info`. The `selectedArchitectureArguments` helper strips the suffix before constructing those tool arguments. This source reading is consistent with the observed absent-`arm64e` diagnostic and the successful direct `otool -h -l -arch arm64e.x1` command; it does not establish a tested fix. ### Additional context - Related completed issue [#674](https://github.com/morluto/rea/issues/674) reported `inspect-macho` passing absent `arm64` arguments for universal arm64e files and discussed tool-specific ABI spellings; this reproduction exposes a remaining or regressed `arm64e.x1` case in which the argument becomes the absent `arm64e` spelling. - Related open issue [#3072](https://github.com/morluto/rea/issues/3072) concerns Hopper selecting an arm64e.x1 slice whose instructions it cannot decode; this report concerns required native static-inspection commands rejecting an architecture argument absent from the input. - Related open issue [#3282](https://github.com/morluto/rea/issues/3282) requests Ghidra support for importing a selected universal slice; this report concerns `inspect-macho`, which admits the file and then fails in a required native command. - Related completed issues [#1168](https://github.com/morluto/rea/issues/1168) and [#1765](https://github.com/morluto/rea/issues/1765) concern variant-name and subtype validation during `inspect-artifact`; this report concerns native inspection after slice selection rather than FAT-table integrity validation.
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#1255
No description provided.