[PR #3284] [CLOSED] fix(native): exclude synthetic entry references from incoming references #5697

Closed
opened 2026-10-31 01:08:44 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/3284
Author: @CryptoKrad
Created: 10/14/2026
Status: ❌ Closed

Base: main ← Head: fix/ghidra-synthetic-entry-incoming-references


📝 Commits (1)

  • 82af2a1 fix(native): exclude synthetic entry references from incoming references

📊 Changes

3 files changed (+22 additions, -26 deletions)

View changed files

📝 bridge/ghidra/ReaGhidraBridge.java (+14 -23)
📝 src/ghidra/GhidraAnalysisProfile.ts (+2 -2)
📝 src/ghidra/GhidraSnapshotCache.test.ts (+6 -1)

📄 Description

Summary

inspect_native_instruction reported Ghidra's synthetic loader entry-point
reference (Entry Point:0x0) as an incoming reference to a program entry, so
the entry function appeared to have a caller. docs/native-investigation.md
documents that Ghidra excludes synthetic entry-point references, and xrefs
already does. This PR restores that contract for exact-address incoming
references. No issue was filed; the failure was found by running
npm run verify:ghidra:windows on a local Windows host.

Problem and expected behavior

Smallest trigger: inspect the entry instruction of any native PE with Ghidra.
The violated invariant, asserted by the real-provider verifier as
synthetic_entry_reference_excluded, is that incoming-reference source
addresses equal xrefs for the same address, with synthetic entry references
excluded.

On the base revision, the real Windows lane fails:

AssertionError: Incoming references differ from xrefs source addresses or their order
+ 'Entry%20Point:0x0',
  '0x1400000a8',
  '0x1400000ac',
  '0x140000194'

Change and scope

Three bridge producers enumerated ReferenceManager.getReferencesTo
independently: xrefs, function-body incoming references, and the
exact-address instruction path added in #1715. The new path omitted the
isEntryPointReference() filter. All three now go through one
visitReferencesTo owner, so the exclusion has one owner. Other
getReferencesTo readers in the bridge are internal flow analysis that keeps
only flow references or body-contained sources. They do not present references
to callers, so they are unchanged.

The instruction_references profile semantics move to
exact-address-incoming-v2. Snapshots captured with the synthetic reference
are refused instead of replayed.

Not included: deduplicating the semantics block that the raw-binary and
executable profile branches both repeat. That duplication predates this change
and covers every key.

Contribution scope: not applicable. This is an ordinary fix within an existing
provider boundary.

Contract and boundary impact

  • Semantic owner and earliest changed stage: Ghidra bridge (ReaGhidraBridge.visitReferencesTo)

  • Contribution scope fit and linked maintainer decision: not applicable (bug fix within the existing contract)

  • CLI and MCP/tool-catalog contract: no schema change. incoming_references no longer contains synthetic entry sources, which matches the documented contract.

  • Provider, bridge, target-format, or platform compatibility: Ghidra only. The behavior does not depend on target format.

  • Evidence, artifact, provenance, or reconstruction contract: the analysis profile semantics are bumped. Older snapshots remain readable, but they are not replayed as current for this facet.

  • Target selection, authority, upstream behavior, and cleanup details: unchanged

  • Generated metadata, package, or installation impact: none

  • Read existing files or captured data.

  • Launch or attach to a process.

  • Inject instrumentation or run scripts/code.

  • Change process memory, registers, files, or configuration.

  • Contact network services.

  • Recover protected code or work around protections.

  • Documentation or usability only; no target interaction.

  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated: GhidraSnapshotCache.test.ts now expects exact-address-incoming-v2 and refuses a v1 snapshot.

  • Base reproduction or other evidence: executed. npm run verify:ghidra:windows fails on the base revision with the assertion above and passes with this change.

  • User-visible CLI/MCP output: for the fixture entry, the incoming-reference sources change from ['Entry%20Point:0x0', '0x1400000a8', '0x1400000ac', '0x140000194'] to ['0x1400000a8', '0x1400000ac', '0x140000194'], equal to xrefs.

  • Remaining proof gaps: the bridge filter has no simulated-provider test, because the Java bridge runs only under real Ghidra. The real-provider verifier is the regression check. Real Ghidra on Linux/macOS was not run.

  • Observed, derived, and inferred claims remain distinguishable.

  • Artifact identity, source provenance, and failed attempts remain preserved.

  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npm run verify:ghidra:windows (Ghidra 12.1.4, JDK 21.0.12, Windows x64 native artifact): before, exit 1 with the assertion above. After, ok: true, synthetic_entry_reference_excluded: true, incoming_xrefs_parity: true, cleanup: complete.
  • npm run verify:ghidra:windows -- --x86: ok: true with the same reference facts, language_id: x86:LE:32:default.
  • npm run check:fast: pass.
  • npx vitest run src/ghidra/GhidraSnapshotCache.test.ts -t "snapshot profile admission": fails before the profile bump (expected v2, received v1), then 6 passed.
  • Related reference and profile tests (15 files): 387 passed and 12 failed. All 12 failures also fail on the unmodified base on this Windows host, because the Linux-declared fixture host receives Windows temp paths. None are new.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Older Ghidra snapshots are reanalyzed instead of replayed for this facet.
  • Real Hopper/Ghidra, browser, or OS coverage: real Ghidra 12.1.4 on Windows x64 for x86-64 and x86 PE. This lane reports compact-reference cli_mcp_parity: false, so CLI/MCP parity was not covered here.
  • Package or release metadata impact: none
  • Security, privacy, process, or containment review: no change to process ownership, containment, or authority

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/3284 **Author:** [@CryptoKrad](https://github.com/CryptoKrad) **Created:** 10/14/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/ghidra-synthetic-entry-incoming-references` --- ### 📝 Commits (1) - [`82af2a1`](https://github.com/morluto/rea/commit/82af2a1066ed6ccf46026b5224afc28f5a2b7047) fix(native): exclude synthetic entry references from incoming references ### 📊 Changes **3 files changed** (+22 additions, -26 deletions) <details> <summary>View changed files</summary> 📝 `bridge/ghidra/ReaGhidraBridge.java` (+14 -23) 📝 `src/ghidra/GhidraAnalysisProfile.ts` (+2 -2) 📝 `src/ghidra/GhidraSnapshotCache.test.ts` (+6 -1) </details> ### 📄 Description ## Summary `inspect_native_instruction` reported Ghidra's synthetic loader entry-point reference (`Entry Point:0x0`) as an incoming reference to a program entry, so the entry function appeared to have a caller. `docs/native-investigation.md` documents that Ghidra excludes synthetic entry-point references, and `xrefs` already does. This PR restores that contract for exact-address incoming references. No issue was filed; the failure was found by running `npm run verify:ghidra:windows` on a local Windows host. ## Problem and expected behavior Smallest trigger: inspect the entry instruction of any native PE with Ghidra. The violated invariant, asserted by the real-provider verifier as `synthetic_entry_reference_excluded`, is that incoming-reference source addresses equal `xrefs` for the same address, with synthetic entry references excluded. On the base revision, the real Windows lane fails: ``` AssertionError: Incoming references differ from xrefs source addresses or their order + 'Entry%20Point:0x0', '0x1400000a8', '0x1400000ac', '0x140000194' ``` ## Change and scope Three bridge producers enumerated `ReferenceManager.getReferencesTo` independently: `xrefs`, function-body incoming references, and the exact-address instruction path added in #1715. The new path omitted the `isEntryPointReference()` filter. All three now go through one `visitReferencesTo` owner, so the exclusion has one owner. Other `getReferencesTo` readers in the bridge are internal flow analysis that keeps only flow references or body-contained sources. They do not present references to callers, so they are unchanged. The `instruction_references` profile semantics move to `exact-address-incoming-v2`. Snapshots captured with the synthetic reference are refused instead of replayed. Not included: deduplicating the semantics block that the raw-binary and executable profile branches both repeat. That duplication predates this change and covers every key. Contribution scope: not applicable. This is an ordinary fix within an existing provider boundary. ## Contract and boundary impact - Semantic owner and earliest changed stage: Ghidra bridge (`ReaGhidraBridge.visitReferencesTo`) - Contribution scope fit and linked maintainer decision: not applicable (bug fix within the existing contract) - CLI and MCP/tool-catalog contract: no schema change. `incoming_references` no longer contains synthetic entry sources, which matches the documented contract. - Provider, bridge, target-format, or platform compatibility: Ghidra only. The behavior does not depend on target format. - Evidence, artifact, provenance, or reconstruction contract: the analysis profile semantics are bumped. Older snapshots remain readable, but they are not replayed as current for this facet. - Target selection, authority, upstream behavior, and cleanup details: unchanged - Generated metadata, package, or installation impact: none - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: `GhidraSnapshotCache.test.ts` now expects `exact-address-incoming-v2` and refuses a `v1` snapshot. - Base reproduction or other evidence: executed. `npm run verify:ghidra:windows` fails on the base revision with the assertion above and passes with this change. - User-visible CLI/MCP output: for the fixture entry, the incoming-reference sources change from `['Entry%20Point:0x0', '0x1400000a8', '0x1400000ac', '0x140000194']` to `['0x1400000a8', '0x1400000ac', '0x140000194']`, equal to `xrefs`. - Remaining proof gaps: the bridge filter has no simulated-provider test, because the Java bridge runs only under real Ghidra. The real-provider verifier is the regression check. Real Ghidra on Linux/macOS was not run. - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npm run verify:ghidra:windows` (Ghidra 12.1.4, JDK 21.0.12, Windows x64 native artifact): before, exit 1 with the assertion above. After, `ok: true`, `synthetic_entry_reference_excluded: true`, `incoming_xrefs_parity: true`, `cleanup: complete`. - `npm run verify:ghidra:windows -- --x86`: `ok: true` with the same reference facts, `language_id: x86:LE:32:default`. - `npm run check:fast`: pass. - `npx vitest run src/ghidra/GhidraSnapshotCache.test.ts -t "snapshot profile admission"`: fails before the profile bump (expected v2, received v1), then 6 passed. - Related reference and profile tests (15 files): 387 passed and 12 failed. All 12 failures also fail on the unmodified base on this Windows host, because the Linux-declared fixture host receives Windows temp paths. None are new. ## Compatibility, safety, and release - Breaking changes or migration steps: none. Older Ghidra snapshots are reanalyzed instead of replayed for this facet. - Real Hopper/Ghidra, browser, or OS coverage: real Ghidra 12.1.4 on Windows x64 for x86-64 and x86 PE. This lane reports compact-reference `cli_mcp_parity: false`, so CLI/MCP parity was not covered here. - Package or release metadata impact: none - Security, privacy, process, or containment review: no change to process ownership, containment, or authority ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:08:44 +00:00
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#5697
No description provided.