[GH-ISSUE #5682] [Bug] Swift dispatch metadata loses enclosing type and module names #3433

Closed
opened 2026-10-31 00:40:26 +00:00 by bsakaguchi · 1 comment
Owner

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

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-native-dispatch-metadata returns four distinct nested Swift conformances as type_name: "Inner", protocol_name: "NP", module: null, and decode.status: "decoded". Their witness-table owners all read Inner: NP; the nested class's vtable owners also omit its enclosing class. The records and addresses remain distinct. The input metadata and demangled witness symbols contain the missing enclosing names and module.

Reproduction

From the built source checkout on the macOS Swift toolchain below:

work_dir="$(mktemp -d)"
mkdir -p "$work_dir"/{home,cfg,data,cache,state,tmp}
cat > "$work_dir/nested.swift" <<'SWIFT'
protocol NP { func z() }
enum A { struct Inner: NP { func z() {} } }
enum B { struct Inner: NP { func z() {} } }
struct Outer { struct Inner: NP { func z() {} } }
class OuterC { class Inner: NP { func z() {} } }
SWIFT
swiftc -Onone -g -parse-as-library -module-name nested \
  -module-cache-path "$work_dir/cache/swift" -emit-library \
  -o "$work_dir/libnested.dylib" "$work_dir/nested.swift"
env -i PATH="$PATH" HOME="$work_dir/home" \
  XDG_CONFIG_HOME="$work_dir/cfg" XDG_DATA_HOME="$work_dir/data" \
  XDG_CACHE_HOME="$work_dir/cache" XDG_STATE_HOME="$work_dir/state" \
  TMPDIR="$work_dir/tmp" REA_LOG_LEVEL=silent \
  node scripts/rea.mjs inspect-native-dispatch-metadata \
  "$work_dir/libnested.dylib" --json > "$work_dir/out.json"
jq -r '.normalized_result.result.swift_conformances[] | [.type_name, .protocol_name, (.module // "null"), .witness_table.address, .decode.status] | @tsv' "$work_dir/out.json"
jq -r '.normalized_result.result.swift_dispatch_slots[] | [.table_kind, .owner] | @tsv' "$work_dir/out.json"
nm "$work_dir/libnested.dylib" | awk '{print $3}' | \
  xcrun swift-demangle --compact | grep 'in conformance' | sort -u

An independent verifier ran this fixture twice; the submitter freshly compiled and replayed it once at the same baseline, with the same result and exit 0. This statically inspects the dylib without executing it.

Expected behavior

Preserve available identity context for the supported simple conformances and class vtables. The returned identities should distinguish A.Inner, B.Inner, Outer.Inner, and OuterC.Inner, with conformance module nested. Witness and class-vtable owners should retain the corresponding context. This expectation does not prescribe whether the module also appears in the name.

The identity-preservation rule requires preserving identity, omission, uncertainty, and source evidence. The documented reader support includes these simple conformances and non-generic class vtables, and says names unavailable in metadata remain null. Here the context is available in the descriptor parent chains.

Impact and scope

P2: callers grouping or attributing records by the returned names and module cannot distinguish these supported nested types. All records and addresses remain available. The demonstrated workaround is to retain address distinctions and consult nm with swift-demangle, which recovers qualified witness names for this unstripped fixture. This does not repair REA's returned identity fields. Prevalence across production binaries and behavior on stripped images or MCP were not tested.

REA version

rea-agents 6.7.0, built source commit 9d8e7803326a382cbbb3ffdb900f5e93e5442d68. Fetched and source-rechecked origin/main at 60956c8c56475e7aaab9559f780908851677ced6: no intervening changes to the cited decoder, schema, or contract files. Current main was not rebuilt or runtime-tested for this submission.

Runtime and platform

Node.js v26.12.0; macOS 27.0.1 arm64; Apple Swift 6.4, swift-driver 1.168.6. Native provider native-macos, version apple-metadata-reader-1; no Hopper/Ghidra required.

Target and artifact context

Self-built thin arm64 Mach-O dylib with debug symbols, four nested types conforming to a local protocol, and a top-level class control. The complete source is inline above.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Observed conformance projection, with columns type, protocol, module, witness address, and decode status:

Inner  NP  null  0x4000  decoded
Inner  NP  null  0x4010  decoded
Inner  NP  null  0x4020  decoded
Inner  NP  null  0x4030  decoded

The slot projection returns four witness_table Inner: NP rows and class-vtable owners OuterC, Inner, Inner. The conformance coverage facet reports complete, examined: 4, decoded: 4, with no name-context limitation.

The independent symbol check returns four distinct witnesses, including:

protocol witness for nested.NP.z() -> () in conformance nested.A.Inner : nested.NP in nested
protocol witness for nested.NP.z() -> () in conformance nested.B.Inner : nested.NP in nested
protocol witness for nested.NP.z() -> () in conformance nested.Outer.Inner : nested.NP in nested
protocol witness for nested.NP.z() -> () in conformance nested.OuterC.Inner : nested.NP in nested

A separate Mach-O byte reader, independently run by the verifier and replayed by the submitter, followed the conformance type descriptors' relative Parent pointers. It recovered Inner -> A -> nested, Inner -> B -> nested, Inner -> Outer -> nested, and Inner -> OuterC -> nested. The final descriptors have kind 0 and name nested; the protocol chain is NP -> nested. This establishes that the missing context exists in the fixture bytes. Evidence provenance: observed; local verification: reproduced.

Typed outcome or recovery expected

Keep all four conformance records and their address relationships while returning distinguishable type identities, module nested, and corresponding qualified slot owners. If context is unsupported or unavailable, expose that limitation instead of silently presenting a complete name attribution. A proposed restoration check should also retain the top-level OuterC control and explicit uncertainty for unsupported parent contexts; no restoration has been tested.

Analysis or suspected cause

Source-derived reasoning: AppleSwiftDispatchFacets.ts reads leaf names and writes module: null; witness owners use those leaves. AppleSwiftVtables.ts likewise uses the leaf class name. These paths do not recover parent descriptor context.

Additional context

Prepared with AI assistance and independently verified. Related #5341 requests populating the separate swift_decls inventory and explicitly excludes conformance records. This report concerns lost identity in existing conformance and slot fields. #4368/#4369 concern malformed empty-name recovery; #5553 concerns symbol-category classification. Separate #5681 concerns vtable coverage units, not name qualification. No earlier known-good version was established.

Originally created by @coygeek on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5682 ### 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-native-dispatch-metadata` returns four distinct nested Swift conformances as `type_name: "Inner"`, `protocol_name: "NP"`, `module: null`, and `decode.status: "decoded"`. Their witness-table owners all read `Inner: NP`; the nested class's vtable owners also omit its enclosing class. The records and addresses remain distinct. The input metadata and demangled witness symbols contain the missing enclosing names and module. ### Reproduction From the built source checkout on the macOS Swift toolchain below: ```sh work_dir="$(mktemp -d)" mkdir -p "$work_dir"/{home,cfg,data,cache,state,tmp} cat > "$work_dir/nested.swift" <<'SWIFT' protocol NP { func z() } enum A { struct Inner: NP { func z() {} } } enum B { struct Inner: NP { func z() {} } } struct Outer { struct Inner: NP { func z() {} } } class OuterC { class Inner: NP { func z() {} } } SWIFT swiftc -Onone -g -parse-as-library -module-name nested \ -module-cache-path "$work_dir/cache/swift" -emit-library \ -o "$work_dir/libnested.dylib" "$work_dir/nested.swift" env -i PATH="$PATH" HOME="$work_dir/home" \ XDG_CONFIG_HOME="$work_dir/cfg" XDG_DATA_HOME="$work_dir/data" \ XDG_CACHE_HOME="$work_dir/cache" XDG_STATE_HOME="$work_dir/state" \ TMPDIR="$work_dir/tmp" REA_LOG_LEVEL=silent \ node scripts/rea.mjs inspect-native-dispatch-metadata \ "$work_dir/libnested.dylib" --json > "$work_dir/out.json" jq -r '.normalized_result.result.swift_conformances[] | [.type_name, .protocol_name, (.module // "null"), .witness_table.address, .decode.status] | @tsv' "$work_dir/out.json" jq -r '.normalized_result.result.swift_dispatch_slots[] | [.table_kind, .owner] | @tsv' "$work_dir/out.json" nm "$work_dir/libnested.dylib" | awk '{print $3}' | \ xcrun swift-demangle --compact | grep 'in conformance' | sort -u ``` An independent verifier ran this fixture twice; the submitter freshly compiled and replayed it once at the same baseline, with the same result and exit 0. This statically inspects the dylib without executing it. ### Expected behavior Preserve available identity context for the supported simple conformances and class vtables. The returned identities should distinguish `A.Inner`, `B.Inner`, `Outer.Inner`, and `OuterC.Inner`, with conformance module `nested`. Witness and class-vtable owners should retain the corresponding context. This expectation does not prescribe whether the module also appears in the name. The [identity-preservation rule](https://github.com/morluto/rea/blob/9d8e7803326a382cbbb3ffdb900f5e93e5442d68/AGENTS.md#architecture-and-cleanup) requires preserving identity, omission, uncertainty, and source evidence. The [documented reader support](https://github.com/morluto/rea/blob/9d8e7803326a382cbbb3ffdb900f5e93e5442d68/docs/native-investigation.md#L419-L427) includes these simple conformances and non-generic class vtables, and says names unavailable in metadata remain null. Here the context is available in the descriptor parent chains. ### Impact and scope P2: callers grouping or attributing records by the returned names and module cannot distinguish these supported nested types. All records and addresses remain available. The demonstrated workaround is to retain address distinctions and consult `nm` with `swift-demangle`, which recovers qualified witness names for this unstripped fixture. This does not repair REA's returned identity fields. Prevalence across production binaries and behavior on stripped images or MCP were not tested. ### REA version `rea-agents` 6.7.0, built source commit `9d8e7803326a382cbbb3ffdb900f5e93e5442d68`. Fetched and source-rechecked `origin/main` at `60956c8c56475e7aaab9559f780908851677ced6`: no intervening changes to the cited decoder, schema, or contract files. Current main was not rebuilt or runtime-tested for this submission. ### Runtime and platform Node.js v26.12.0; macOS 27.0.1 arm64; Apple Swift 6.4, swift-driver 1.168.6. Native provider `native-macos`, version `apple-metadata-reader-1`; no Hopper/Ghidra required. ### Target and artifact context Self-built thin arm64 Mach-O dylib with debug symbols, four nested types conforming to a local protocol, and a top-level class control. The complete source is inline above. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Observed conformance projection, with columns type, protocol, module, witness address, and decode status: ```text Inner NP null 0x4000 decoded Inner NP null 0x4010 decoded Inner NP null 0x4020 decoded Inner NP null 0x4030 decoded ``` The slot projection returns four `witness_table Inner: NP` rows and class-vtable owners `OuterC`, `Inner`, `Inner`. The conformance coverage facet reports `complete`, `examined: 4`, `decoded: 4`, with no name-context limitation. The independent symbol check returns four distinct witnesses, including: ```text protocol witness for nested.NP.z() -> () in conformance nested.A.Inner : nested.NP in nested protocol witness for nested.NP.z() -> () in conformance nested.B.Inner : nested.NP in nested protocol witness for nested.NP.z() -> () in conformance nested.Outer.Inner : nested.NP in nested protocol witness for nested.NP.z() -> () in conformance nested.OuterC.Inner : nested.NP in nested ``` A separate Mach-O byte reader, independently run by the verifier and replayed by the submitter, followed the conformance type descriptors' relative Parent pointers. It recovered `Inner -> A -> nested`, `Inner -> B -> nested`, `Inner -> Outer -> nested`, and `Inner -> OuterC -> nested`. The final descriptors have kind 0 and name `nested`; the protocol chain is `NP -> nested`. This establishes that the missing context exists in the fixture bytes. Evidence provenance: observed; local verification: reproduced. ### Typed outcome or recovery expected Keep all four conformance records and their address relationships while returning distinguishable type identities, module `nested`, and corresponding qualified slot owners. If context is unsupported or unavailable, expose that limitation instead of silently presenting a complete name attribution. A proposed restoration check should also retain the top-level `OuterC` control and explicit uncertainty for unsupported parent contexts; no restoration has been tested. ### Analysis or suspected cause Source-derived reasoning: [AppleSwiftDispatchFacets.ts](https://github.com/morluto/rea/blob/9d8e7803326a382cbbb3ffdb900f5e93e5442d68/src/native/AppleSwiftDispatchFacets.ts#L114-L143) reads leaf names and writes `module: null`; [witness owners](https://github.com/morluto/rea/blob/9d8e7803326a382cbbb3ffdb900f5e93e5442d68/src/native/AppleSwiftDispatchFacets.ts#L198) use those leaves. [AppleSwiftVtables.ts](https://github.com/morluto/rea/blob/9d8e7803326a382cbbb3ffdb900f5e93e5442d68/src/native/AppleSwiftVtables.ts#L68-L94) likewise uses the leaf class name. These paths do not recover parent descriptor context. ### Additional context Prepared with AI assistance and independently verified. Related #5341 requests populating the separate `swift_decls` inventory and explicitly excludes conformance records. This report concerns lost identity in existing conformance and slot fields. #4368/#4369 concern malformed empty-name recovery; #5553 concerns symbol-category classification. Separate #5681 concerns vtable coverage units, not name qualification. No earlier known-good version was established.
Author
Owner

@matbrgz commented on GitHub (Oct 20, 2026):

Cross-referencing with canonical issue #4368 ([Bug] Empty Swift conformance names escape entry recovery and invalidate dispatch metadata) and sibling Swift dispatch metadata reports #5424, #5529, #5543, #5681, #5683, #5685.

Consolidated under Cluster AZ (Native Dispatch Metadata Inspection & Provider Fallbacks) in tracker #4330.

<!-- gh-comment-id:6303855943 --> @matbrgz commented on GitHub (Oct 20, 2026): Cross-referencing with canonical issue #4368 (`[Bug] Empty Swift conformance names escape entry recovery and invalidate dispatch metadata`) and sibling Swift dispatch metadata reports #5424, #5529, #5543, #5681, #5683, #5685. Consolidated under **Cluster AZ (Native Dispatch Metadata Inspection & Provider Fallbacks)** in tracker #4330.
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#3433
No description provided.