[GH-ISSUE #6648] [Bug] Mach-O import inventory treats chained binding addends as symbol names #4027

Closed
opened 2026-10-31 00:46:11 +00:00 by bsakaguchi · 0 comments
Owner

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

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

A synthetic dyld_info -imports row for symbol _fixture_data with addend 4 becomes an import named _fixture_data+0x4. The parser retains the display expression as the symbol identity. With zero-addend and nonzero-addend bindings to the same symbol, the normalized inventory reports two different names.

Observed at the parser boundary and through production inspectNativeMacho with injected command captures. No real Apple command, public CLI, or MCP request was executed.

Reproduction

Executed a standalone Node.js script importing parseDyldSymbols from the checked-out TypeScript source and separately from the parser extracted using git show rea-agents-6.7.0:src/native/parsers/dyldInfo.ts. The essential call in that script was:

const rows = [
  '    -imports:',
  '      0x0000  _fixture_data  (from libFixture)',
  '      0x0001  _fixture_data+0x4  (from libFixture)',
  '      0x0002  _fixture_weak+0x8 [weak-import] (from libFixture)',
].join('\n') + '\n';
const result = parseDyldSymbols(rows, 'imports');

Both parser versions returned the names shown below. Each was run once, with assertions confirming the ordinary-name control, incorrect suffixed names, source library, and weak-import flag.

A second script invoked production inspectNativeMacho with NativeFixtureRunner, overriding only dyld_info:-imports with the first two rows and using the repository's other command fixtures. Its successful normalized result retained both _fixture_data and _fixture_data+0x4. This consumer-boundary probe ran once successfully using Node's native TypeScript transform and a resolving hook for source .js imports.

Expected behavior

Preserve _fixture_data as the imported symbol's identity. A binding addend is separate metadata, not part of that name. If the textual representation cannot be disambiguated, report that uncertainty rather than assert a synthesized symbol identity; blindly stripping suffixes from arbitrary literal symbol names would also lose identity.

Apple's dyld-1378 producer implementation prints target.symbolName and target.addend separately, adding the hexadecimal suffix only for nonzero addends. REA's repository contract requires preserving identity and source values across boundaries.

Impact and scope

P2: incorrect import identities for the bounded class of chained imports with nonzero bind-target addends. A symbol can appear under multiple names solely because its binding addends differ, making exact inventory matching or comparison incorrect. The zero-addend control works. The input artifact is not modified.

Real-binary frequency, affected macOS toolchain versions, and public CLI/MCP behavior are NOT_ENOUGH_INFO: this Linux investigation used synthetic producer-shaped rows rather than a compiled Mach-O and live Apple tools.

REA version

Main 23def04096869b85c4d3c14a73ed09168483c9f6, package 6.7.0. The parser extracted from release tag rea-agents-6.7.0 (27dc42d10249f0410904a75c0997842eb03b931c) also reproduced the defect. The release-to-main parser diff changes line handling and export parsing, leaving this import-name assignment unchanged. This establishes the release source-parser defect, not an executed packaged-release CLI reproduction.

Runtime and platform

Node.js v24.22.1; Linux x86_64. Native type stripping for the parser probe; experimental native type transformation and a source-resolution hook for the consumer probe. No Hopper, Ghidra, or macOS tool execution.

Target and artifact context

Clean generated text fixtures representing Mach-O chained bindings. All names and library labels are synthetic. No target executable was read or run.

Interface

Other — parser and production native normalization boundaries.

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Observed parser names on both main and release source:

["_fixture_data", "_fixture_data+0x4", "_fixture_weak+0x8"]

Observed production-normalizer import items with injected captures:

[
  {"name":"_fixture_data","address":null,"weak":null,"reexport":null,"source":"libFixture"},
  {"name":"_fixture_data+0x4","address":null,"weak":null,"reexport":null,"source":"libFixture"}
]

The normalized inventory reports incomplete coverage, but its limitation concerns omitted metadata and does not identify these names as expressions or uncertain identities.

Parser assignment, production consumer, and symbol result schema establish the path from the textual expression into the returned name field. Evidence provenance: observed synthetic parser/consumer behavior plus source-derived Apple output semantics.

Typed outcome or recovery expected

Retain the correct imported symbol name with separately represented addend information or an explicit uncertainty/limitation where exact identity cannot be established. Preserve the zero-addend and weak-import controls. No fix was implemented or verified.

Analysis or suspected cause

Source-derived: the import regex captures the complete expression before the optional weak annotation and (from ...), then assigns it directly to name. It does not model Apple's nonzero-addend formatting branch. The release import parser has the same assignment.

Additional context

Open-and-closed searches included dyld, addend, dyld addend, chained import, and import +0x. No matching report was found. #3390 concerns carriage returns in export names; #5298 concerns runtime breakpoint image attribution; closed #563 lists other parser-admission problems and does not cover import addends.

NOT_ENOUGH_INFO: no last-known-good version was established. A live macOS reproduction using a generated Mach-O with a nonzero chained bind-target addend remains unperformed.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Synthetic valid producer-shaped rows repeatedly give incorrect imported-symbol identities in the parser and production normalizer; the release parser has the same observed defect. Reach is bounded to nonzero bind-target addends, with real-world frequency unmeasured.
  • Workaround status: unverified
  • Workaround basis: Native binding metadata may recover the separate symbol and addend, but no real macOS tool workflow or equivalent REA workaround was executed on this Linux host.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6648 ### 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 A synthetic `dyld_info -imports` row for symbol `_fixture_data` with addend 4 becomes an import named `_fixture_data+0x4`. The parser retains the display expression as the symbol identity. With zero-addend and nonzero-addend bindings to the same symbol, the normalized inventory reports two different names. Observed at the parser boundary and through production `inspectNativeMacho` with injected command captures. No real Apple command, public CLI, or MCP request was executed. ### Reproduction Executed a standalone Node.js script importing `parseDyldSymbols` from the checked-out TypeScript source and separately from the parser extracted using `git show rea-agents-6.7.0:src/native/parsers/dyldInfo.ts`. The essential call in that script was: ```js const rows = [ ' -imports:', ' 0x0000 _fixture_data (from libFixture)', ' 0x0001 _fixture_data+0x4 (from libFixture)', ' 0x0002 _fixture_weak+0x8 [weak-import] (from libFixture)', ].join('\n') + '\n'; const result = parseDyldSymbols(rows, 'imports'); ``` Both parser versions returned the names shown below. Each was run once, with assertions confirming the ordinary-name control, incorrect suffixed names, source library, and weak-import flag. A second script invoked production `inspectNativeMacho` with `NativeFixtureRunner`, overriding only `dyld_info:-imports` with the first two rows and using the repository's other command fixtures. Its successful normalized result retained both `_fixture_data` and `_fixture_data+0x4`. This consumer-boundary probe ran once successfully using Node's native TypeScript transform and a resolving hook for source `.js` imports. ### Expected behavior Preserve `_fixture_data` as the imported symbol's identity. A binding addend is separate metadata, not part of that name. If the textual representation cannot be disambiguated, report that uncertainty rather than assert a synthesized symbol identity; blindly stripping suffixes from arbitrary literal symbol names would also lose identity. Apple's [dyld-1378 producer implementation](https://github.com/apple-oss-distributions/dyld/blob/fd8d0c4d52320ebf64db34f3cb280310d905c5ae/other-tools/dyld_info.cpp#L490-L503) prints `target.symbolName` and `target.addend` separately, adding the hexadecimal suffix only for nonzero addends. REA's [repository contract](https://github.com/morluto/rea/blob/23def04096869b85c4d3c14a73ed09168483c9f6/AGENTS.md) requires preserving identity and source values across boundaries. ### Impact and scope P2: incorrect import identities for the bounded class of chained imports with nonzero bind-target addends. A symbol can appear under multiple names solely because its binding addends differ, making exact inventory matching or comparison incorrect. The zero-addend control works. The input artifact is not modified. Real-binary frequency, affected macOS toolchain versions, and public CLI/MCP behavior are NOT_ENOUGH_INFO: this Linux investigation used synthetic producer-shaped rows rather than a compiled Mach-O and live Apple tools. ### REA version Main `23def04096869b85c4d3c14a73ed09168483c9f6`, package 6.7.0. The parser extracted from release tag `rea-agents-6.7.0` (`27dc42d10249f0410904a75c0997842eb03b931c`) also reproduced the defect. The release-to-main parser diff changes line handling and export parsing, leaving this import-name assignment unchanged. This establishes the release source-parser defect, not an executed packaged-release CLI reproduction. ### Runtime and platform Node.js v24.22.1; Linux x86_64. Native type stripping for the parser probe; experimental native type transformation and a source-resolution hook for the consumer probe. No Hopper, Ghidra, or macOS tool execution. ### Target and artifact context Clean generated text fixtures representing Mach-O chained bindings. All names and library labels are synthetic. No target executable was read or run. ### Interface Other — parser and production native normalization boundaries. ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Observed parser names on both main and release source: ```json ["_fixture_data", "_fixture_data+0x4", "_fixture_weak+0x8"] ``` Observed production-normalizer import items with injected captures: ```json [ {"name":"_fixture_data","address":null,"weak":null,"reexport":null,"source":"libFixture"}, {"name":"_fixture_data+0x4","address":null,"weak":null,"reexport":null,"source":"libFixture"} ] ``` The normalized inventory reports incomplete coverage, but its limitation concerns omitted metadata and does not identify these names as expressions or uncertain identities. [Parser assignment](https://github.com/morluto/rea/blob/23def04096869b85c4d3c14a73ed09168483c9f6/src/native/parsers/dyldInfo.ts#L23-L35), [production consumer](https://github.com/morluto/rea/blob/23def04096869b85c4d3c14a73ed09168483c9f6/src/native/NativeMachoInspection.ts#L243-L251), and [symbol result schema](https://github.com/morluto/rea/blob/23def04096869b85c4d3c14a73ed09168483c9f6/src/domain/native/nativeInspection.ts#L73-L79) establish the path from the textual expression into the returned `name` field. Evidence provenance: observed synthetic parser/consumer behavior plus source-derived Apple output semantics. ### Typed outcome or recovery expected Retain the correct imported symbol name with separately represented addend information or an explicit uncertainty/limitation where exact identity cannot be established. Preserve the zero-addend and weak-import controls. No fix was implemented or verified. ### Analysis or suspected cause Source-derived: the import regex captures the complete expression before the optional weak annotation and `(from ...)`, then assigns it directly to `name`. It does not model Apple's nonzero-addend formatting branch. The release [import parser](https://github.com/morluto/rea/blob/27dc42d10249f0410904a75c0997842eb03b931c/src/native/parsers/dyldInfo.ts#L21-L33) has the same assignment. ### Additional context Open-and-closed searches included `dyld`, `addend`, `dyld addend`, `chained import`, and `import +0x`. No matching report was found. [#3390](https://github.com/morluto/rea/issues/3390) concerns carriage returns in export names; [#5298](https://github.com/morluto/rea/issues/5298) concerns runtime breakpoint image attribution; closed [#563](https://github.com/morluto/rea/issues/563) lists other parser-admission problems and does not cover import addends. NOT_ENOUGH_INFO: no last-known-good version was established. A live macOS reproduction using a generated Mach-O with a nonzero chained bind-target addend remains unperformed. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Synthetic valid producer-shaped rows repeatedly give incorrect imported-symbol identities in the parser and production normalizer; the release parser has the same observed defect. Reach is bounded to nonzero bind-target addends, with real-world frequency unmeasured. - Workaround status: unverified - Workaround basis: Native binding metadata may recover the separate symbol and addend, but no real macOS tool workflow or equivalent REA workaround was executed on this Linux host.
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#4027
No description provided.