[GH-ISSUE #4195] [Bug] inspect-macho reports a missing UUID row for a valid arm64e.v1 slice #1646

Closed
opened 2026-10-16 21:08:23 +00:00 by bsakaguchi · 2 comments
Owner

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Observed behavior

inspect-macho returns a false missing-dwarfdump-row limitation when it selects the arm64e.v1 slice of a source-built universal Mach-O. Real lipo names that slice arm64e.v1; real dwarfdump --uuid --arch=arm64e prints its matching UUID under (arm64e). The returned UUID is correct. The defect is incorrect uncertainty metadata in successful Evidence.

Reproduction

Use the source baseline and toolchain stated under REA version and Runtime and platform on an arm64 Mac with the locked dependencies installed. Build the runtime with npm run build:cached, then run these commands from the repository root. This compiler's ordinary -arch arm64e output has pointer-auth ABI version 1, which the FAT lipo listing below verifies. The equivalent commands were executed locally; generated UUID values may differ.

rea_root="$PWD"
probe_root="$(mktemp -d -t arm64e-uuid-repro)"
cd "$probe_root"
mkdir home config
cat > fixture.c <<'C'
int main(void) { return 0; }
C
clang -arch arm64e fixture.c -o fixture-arm64e-default
clang -arch x86_64 fixture.c -o fixture-x86_64
lipo -create fixture-arm64e-default fixture-x86_64 -output fixture-universal-default
lipo -detailed_info fixture-universal-default
xcrun dwarfdump --uuid --arch=arm64e fixture-universal-default
xcrun otool -h -l -arch arm64e fixture-universal-default
env HOME="$PWD/home" XDG_CONFIG_HOME="$PWD/config"   node "$rea_root/scripts/rea.mjs" inspect-macho "$PWD/fixture-universal-default" --format json > universal.json
python3 - <<'PYTHON'
import json
result = json.load(open("universal.json"))["normalized_result"]
print(json.dumps({key: result[key] for key in
    ["selected_architecture", "uuid", "limitations"]}, indent=2))
PYTHON

Check that lipo lists both x86_64 and arm64e.v1, with capabilities PTR_AUTH_VERSION USERSPACE 1 on the latter. Compare the dwarfdump row and otool's LC_UUID with the returned uuid and limitation. Repeat the CLI call on the same file. As a discriminating control, extract the same slice and inspect it separately.

lipo -thin arm64e fixture-universal-default -output fixture-thin
env HOME="$PWD/home" XDG_CONFIG_HOME="$PWD/config"   node "$rea_root/scripts/rea.mjs" inspect-macho "$PWD/fixture-thin" --format json > thin.json
python3 - <<'PYTHON'
import json
result = json.load(open("thin.json"))["normalized_result"]
print(json.dumps({key: result[key] for key in
    ["selected_architecture", "uuid", "limitations"]}, indent=2))
PYTHON

Expected behavior

The normalized inspection describes the selected image and reconciles that slice's UUID observations. For this valid slice, the successful selected-slice dwarfdump command returns an (arm64e) row agreeing with LC_UUID. Preserve the UUID and exact arm64e.v1 selection without claiming that the row is missing. Keep malformed, ambiguous, unrelated-slice and conflicting observations distinguishable. The selected-image contract and UUID reconciliation contract ground this expectation.

Impact and scope

P2, supported. The same universal artifact reproduced the false limitation twice; its UUID remained correct and usable. No UUID loss or blocked core workflow was observed. Native-tool corroboration does not correct the returned Evidence, and thinning changes the selected artifact, digest and container coordinates. No demonstrated workaround restores truthful UUID reconciliation for the original universal artifact.

REA version

Source checkout 62bf09809ef7bb224028916424f8f07652a20f4f, freshly built; launcher reports 6.5.0. This is source-checkout verification, not an installed released-package reproduction. Relevant source is unchanged on current main c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb, inspected rather than runtime-reproduced at that revision.

Runtime and platform

Node v24.18.0, npm 11.16.0, macOS 27.0.1 arm64, Xcode 27.0 build 27A266a, Apple clang 21.0.0 clang-2100.3.34.2, dwarfdump Apple LLVM 21.0.0, otool cctools-1040.

Target and artifact context

Benign source-built universal Mach-O containing x86_64 and arm64e.v1 slices; selected container offset 16384. The toy executable was compiled and inspected, never executed. The thin control contains the same selected image but is a different artifact.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Both CLI invocations on the same universal fixture exited 0 and returned this relevant subset. Real dwarfdump printed 75A359E9-3607-3247-ADFC-6049C415F804 (arm64e) for the selected slice, and otool printed that same UUID in LC_UUID.

{
  "selected_architecture": {
    "name": "arm64e.v1",
    "container_file_offset": 16384
  },
  "uuid": "75A359E9-3607-3247-ADFC-6049C415F804",
  "limitations": [
    "dwarfdump --uuid returned no row for selected architecture arm64e.v1; using the unambiguous otool LC_UUID."
  ]
}

Only the affected UUID member of normalized_result.limitations is shown above; unrelated import/export and build-metadata limitations are omitted. Returned command provenance records dwarfdump --uuid --arch=arm64e and otool -h -l -arch arm64e, both with exit code 0, while dyld_info correctly receives -arch arm64e.v1. The thin-slice control exited 0 with selected architecture arm64e, offset zero, the same UUID and no missing-row limitation. Thinning changes the subject digest and container coordinates, so that control does not repair the original universal artifact's Evidence.

A separate real fixture linked without LC_UUID produced no dwarfdump UUID row and the CLI failed earlier because dyld_info reported missing LC_UUID load command. This report does not claim a real-artifact UUID-loss case. MCP transport, other hosts, other Apple toolchain versions and arbitrary arm64e ABI variants were not executed.

Evidence provenance: observed. Local verification: reproduced. Reproduction completeness: complete for the stated CLI case. Production CLI execution used isolated HOME/config and real Apple tools, without an injected provider or command runner. The selected checkout build passed; existing focused checks for NativeMachoInspection and nativeSelectedArchitecture passed 35 tests in two files. Those deterministic tests do not establish real-tool correctness for this spelling difference.

Typed outcome or recovery expected

Successful Evidence should retain the same selected arm64e.v1 identity, container offset and matching UUID without a missing-row or fallback-only UUID limitation. The thin control should remain correct. Preserve uncertainty for malformed, ambiguous, unrelated-slice and conflicting observations; accepting the real selected-slice spelling must not accept an arbitrary architecture row. Empty dwarfdump output remains an absent observation under the existing contract.

Analysis or suspected cause

The normalizer passes the exact selected variant name to reconciliation, whose row selection requires exact equality with the dwarfdump architecture. Meanwhile, tool argument selection strips .v1 for dwarfdump and otool while preserving it for dyld_info. This source-derived explanation agrees with the observed commands and false diagnostic; it does not establish a UUID-loss scenario.

Additional context

Closure requires rerunning the original universal artifact case and retaining its exact variant selection and coordinates. MCP transport, other hosts, other Apple toolchain versions and arbitrary arm64e ABI variants were not executed. No fix or successful restoration has been tested.

Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4195 ### 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 Evidence, artifacts, or reconstruction ### Observed behavior `inspect-macho` returns a false missing-dwarfdump-row limitation when it selects the `arm64e.v1` slice of a source-built universal Mach-O. Real lipo names that slice `arm64e.v1`; real `dwarfdump --uuid --arch=arm64e` prints its matching UUID under `(arm64e)`. The returned UUID is correct. The defect is incorrect uncertainty metadata in successful Evidence. ### Reproduction Use the source baseline and toolchain stated under REA version and Runtime and platform on an arm64 Mac with the locked dependencies installed. Build the runtime with `npm run build:cached`, then run these commands from the repository root. This compiler's ordinary `-arch arm64e` output has pointer-auth ABI version 1, which the FAT lipo listing below verifies. The equivalent commands were executed locally; generated UUID values may differ. ```sh rea_root="$PWD" probe_root="$(mktemp -d -t arm64e-uuid-repro)" cd "$probe_root" mkdir home config cat > fixture.c <<'C' int main(void) { return 0; } C clang -arch arm64e fixture.c -o fixture-arm64e-default clang -arch x86_64 fixture.c -o fixture-x86_64 lipo -create fixture-arm64e-default fixture-x86_64 -output fixture-universal-default lipo -detailed_info fixture-universal-default xcrun dwarfdump --uuid --arch=arm64e fixture-universal-default xcrun otool -h -l -arch arm64e fixture-universal-default env HOME="$PWD/home" XDG_CONFIG_HOME="$PWD/config" node "$rea_root/scripts/rea.mjs" inspect-macho "$PWD/fixture-universal-default" --format json > universal.json python3 - <<'PYTHON' import json result = json.load(open("universal.json"))["normalized_result"] print(json.dumps({key: result[key] for key in ["selected_architecture", "uuid", "limitations"]}, indent=2)) PYTHON ``` Check that lipo lists both `x86_64` and `arm64e.v1`, with `capabilities PTR_AUTH_VERSION USERSPACE 1` on the latter. Compare the dwarfdump row and otool's `LC_UUID` with the returned `uuid` and limitation. Repeat the CLI call on the same file. As a discriminating control, extract the same slice and inspect it separately. ```sh lipo -thin arm64e fixture-universal-default -output fixture-thin env HOME="$PWD/home" XDG_CONFIG_HOME="$PWD/config" node "$rea_root/scripts/rea.mjs" inspect-macho "$PWD/fixture-thin" --format json > thin.json python3 - <<'PYTHON' import json result = json.load(open("thin.json"))["normalized_result"] print(json.dumps({key: result[key] for key in ["selected_architecture", "uuid", "limitations"]}, indent=2)) PYTHON ``` ### Expected behavior The normalized inspection describes the selected image and reconciles that slice's UUID observations. For this valid slice, the successful selected-slice dwarfdump command returns an `(arm64e)` row agreeing with `LC_UUID`. Preserve the UUID and exact `arm64e.v1` selection without claiming that the row is missing. Keep malformed, ambiguous, unrelated-slice and conflicting observations distinguishable. The [selected-image contract](https://github.com/morluto/rea/blob/c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb/docs/native-investigation.md#L262-L278) and [UUID reconciliation contract](https://github.com/morluto/rea/blob/c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb/src/native/parsers/machoUuid.ts#L10-L24) ground this expectation. ### Impact and scope P2, supported. The same universal artifact reproduced the false limitation twice; its UUID remained correct and usable. No UUID loss or blocked core workflow was observed. Native-tool corroboration does not correct the returned Evidence, and thinning changes the selected artifact, digest and container coordinates. No demonstrated workaround restores truthful UUID reconciliation for the original universal artifact. ### REA version Source checkout [62bf09809ef7bb224028916424f8f07652a20f4f](https://github.com/morluto/rea/commit/62bf09809ef7bb224028916424f8f07652a20f4f), freshly built; launcher reports 6.5.0. This is source-checkout verification, not an installed released-package reproduction. Relevant source is unchanged on current main `c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb`, inspected rather than runtime-reproduced at that revision. ### Runtime and platform Node v24.18.0, npm 11.16.0, macOS 27.0.1 arm64, Xcode 27.0 build 27A266a, Apple clang 21.0.0 clang-2100.3.34.2, dwarfdump Apple LLVM 21.0.0, otool cctools-1040. ### Target and artifact context Benign source-built universal Mach-O containing x86_64 and arm64e.v1 slices; selected container offset 16384. The toy executable was compiled and inspected, never executed. The thin control contains the same selected image but is a different artifact. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Both CLI invocations on the same universal fixture exited 0 and returned this relevant subset. Real dwarfdump printed `75A359E9-3607-3247-ADFC-6049C415F804 (arm64e)` for the selected slice, and otool printed that same UUID in `LC_UUID`. ```json { "selected_architecture": { "name": "arm64e.v1", "container_file_offset": 16384 }, "uuid": "75A359E9-3607-3247-ADFC-6049C415F804", "limitations": [ "dwarfdump --uuid returned no row for selected architecture arm64e.v1; using the unambiguous otool LC_UUID." ] } ``` Only the affected UUID member of `normalized_result.limitations` is shown above; unrelated import/export and build-metadata limitations are omitted. Returned command provenance records `dwarfdump --uuid --arch=arm64e` and `otool -h -l -arch arm64e`, both with exit code 0, while dyld_info correctly receives `-arch arm64e.v1`. The thin-slice control exited 0 with selected architecture `arm64e`, offset zero, the same UUID and no missing-row limitation. Thinning changes the subject digest and container coordinates, so that control does not repair the original universal artifact's Evidence. A separate real fixture linked without `LC_UUID` produced no dwarfdump UUID row and the CLI failed earlier because dyld_info reported `missing LC_UUID load command`. This report does not claim a real-artifact UUID-loss case. MCP transport, other hosts, other Apple toolchain versions and arbitrary arm64e ABI variants were not executed. Evidence provenance: observed. Local verification: reproduced. Reproduction completeness: complete for the stated CLI case. Production CLI execution used isolated HOME/config and real Apple tools, without an injected provider or command runner. The selected checkout build passed; existing focused checks for `NativeMachoInspection` and `nativeSelectedArchitecture` passed 35 tests in two files. Those deterministic tests do not establish real-tool correctness for this spelling difference. ### Typed outcome or recovery expected Successful Evidence should retain the same selected `arm64e.v1` identity, container offset and matching UUID without a missing-row or fallback-only UUID limitation. The thin control should remain correct. Preserve uncertainty for malformed, ambiguous, unrelated-slice and conflicting observations; accepting the real selected-slice spelling must not accept an arbitrary architecture row. Empty dwarfdump output remains an absent observation under the existing contract. ### Analysis or suspected cause The [normalizer](https://github.com/morluto/rea/blob/c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb/src/native/NativeMachoInspection.ts#L235-L241) passes the exact selected variant name to reconciliation, whose [row selection](https://github.com/morluto/rea/blob/c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb/src/native/parsers/machoUuid.ts#L92-L127) requires exact equality with the dwarfdump architecture. Meanwhile, [tool argument selection](https://github.com/morluto/rea/blob/c7f6b8bad1a34d5efb30ff2a017672dea1fcdabb/src/native/NativeMachoInspection.ts#L431-L450) strips `.v1` for dwarfdump and otool while preserving it for dyld_info. This source-derived explanation agrees with the observed commands and false diagnostic; it does not establish a UUID-loss scenario. ### Additional context Closure requires rerunning the original universal artifact case and retaining its exact variant selection and coordinates. MCP transport, other hosts, other Apple toolchain versions and arbitrary arm64e ABI variants were not executed. No fix or successful restoration has been tested.
Author
Owner

@Henglie commented on GitHub (Oct 15, 2026):

Opened a draft PR for this: https://github.com/morluto/rea/pull/4288

The row comparison in src/native/parsers/machoUuid.ts used string equality, so a correct (arm64e) row never matched the arm64e.v1 selection even though the slice tools are already invoked with the pointer-auth ABI version stripped (toolArchitectureName in NativeMachoInspection.ts). The fix compares family names and leaves other variants such as arm64e.x1 matching exactly, since those are distinct subtypes rather than a version spelling.

Not reproduced on macOS here — no arm64e toolchain available — so the regression sits at the parser boundary the report identifies, and that gap is recorded in the PR.

<!-- gh-comment-id:6204649144 --> @Henglie commented on GitHub (Oct 15, 2026): Opened a draft PR for this: https://github.com/morluto/rea/pull/4288 The row comparison in `src/native/parsers/machoUuid.ts` used string equality, so a correct `(arm64e)` row never matched the `arm64e.v1` selection even though the slice tools are already invoked with the pointer-auth ABI version stripped (`toolArchitectureName` in `NativeMachoInspection.ts`). The fix compares family names and leaves other variants such as `arm64e.x1` matching exactly, since those are distinct subtypes rather than a version spelling. Not reproduced on macOS here — no arm64e toolchain available — so the regression sits at the parser boundary the report identifies, and that gap is recorded in the PR.
Author
Owner

@morluto commented on GitHub (Oct 16, 2026):

Fixed on main in 2f6b9ecdc. UUID reconciliation keeps selected slice identity separate from dwarfdump architecture spelling, accepting the matching arm64e row for the selected arm64e.v1 slice without erasing explicit ABI-version differences.

Production-boundary regressions cover the reported row, wrong-version/mixed-row controls and fallback/conflicts. Post-fix real Apple multi-version behavior was not rerun.

Hosted main CI is still pending; this closure is based on the implemented fix and the scoped regression evidence.

<!-- gh-comment-id:6206037522 --> @morluto commented on GitHub (Oct 16, 2026): Fixed on `main` in [2f6b9ecdc](https://github.com/morluto/rea/commit/2f6b9ecdc6a0680117898194fbeb4e513080d6f7). UUID reconciliation keeps selected slice identity separate from dwarfdump architecture spelling, accepting the matching arm64e row for the selected arm64e.v1 slice without erasing explicit ABI-version differences. Production-boundary regressions cover the reported row, wrong-version/mixed-row controls and fallback/conflicts. Post-fix real Apple multi-version behavior was not rerun. Hosted main CI is still pending; this closure is based on the implemented fix and the scoped regression evidence.
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#1646
No description provided.