mirror of
https://github.com/morluto/rea.git
synced 2026-11-05 06:45:22 +00:00
[GH-ISSUE #8277] [Bug] Resolved Ghidra indirect reference can yield a definite negative call path #6517
Open
opened 2026-11-01 21:11:51 +00:00 by bsakaguchi
·
13 comments
No Branch/Tag specified
main
codex/procedure-reference-stacked
release-please--branches--main--components--rea-agents
release-please--branches--main--components--rea-agents--release-notes
codex/kuna-independent-retry
codex/byte-search-overlay-coverage
codex/open-failure-target-receipt
codex/kuna-xref-evidence
codex/ghidra-ambiguous-procedure-recovery
codex/function-source-bundle
codex/trace-function-integration-prototype
codex/snapshot-source-closure
codex/recorded-evidence-array-pages
codex/evidence-recovery-redesign
codex/trace-feature-address-scope
codex/call-discovery-scope
codex/ghidra-literal-candidate-evidence
codex/decompile-directory-independent-retry
codex/retry-provenance-base
codex/value-flow-capability-experiment
codex/ghidra-containing-instruction
cursor/readme-discord-button-ef9f
dependabot/github_actions/actions/setup-node-7.1.0
dependabot/github_actions/actions/upload-artifact-7.0.2
dependabot/npm_and_yarn/npm-minor-and-patch-d8d97ce6df
codex/kuna-1989
fix/8559-native-ui-fixture-ownership
fix/8555-go-verifier-mcp-ownership
codex/provider-capability-recovery
fix/8642-rizin-target-stdin
codex/ghidra-memory-effect-scope
codex/ghidra-annotation-entry-selector
codex/ghidra-readonly-recovery
codex/ghidra-regex-verifier-recovery
codex/evidence-discovery-view-guidance
fix/8545-bulk-append-overflow
fix/8428-navigation-refusal-alternatives
codex/address-context-recovery
codex/matching-member-limitations
codex/unknown-scope-contract
codex/evidence-view-guidance
feat/8373-native-trace-views
codex/ghidra-snapshot-verifier-binding
codex/elf-export-visibility
codex/evidence-view-recovery
codex/native-reference-cli-help
codex/provider-candidate-observation-scope
codex/kuna-session-verification
codex/ghidra-switch-lifetime-guidance
codex/pseudocode-paging-discovery
codex/clarify-evidence-view-support
codex/kuna-xrefs-selector-recovery
codex/context-capacity-recovery
codex/evidence-closure-large-links
codex/same-function-evidence-identity
codex/ghidra-verifier-inspected-jdk
codex/audit-guided-workflows
codex/crash-prompt-retained-dossiers
codex/analysis-view-error-recovery
codex/kuna-verifier-target-selection
codex/ghidra-selected-project-call-coverage
codex/docs-native-analysis-scope
codex/ghidra-java-socket-boundary
codex/ghidra-retained-snapshot-verifier
codex/ghidra-search-inventory-facts
fix/8284-zero-argument-parameter-bindings
fix/8198-ui-action-handler-offset
fix/8257-elf-entry-label-identity
fix/8304-deferred-output-schema-projection
fix/8277-call-path-computed-target-uncertainty
fix/pr-8089-conflicts
fix/ci-static-duplicate-export
dependabot/npm_and_yarn/lint-staged-17.6.0
dependabot/github_actions/actions/download-artifact-8.0.2
dependabot/npm_and_yarn/write-file-atomic-8.0.0
dependabot/npm_and_yarn/canonicalize-5.1.0
dependabot/github_actions/actions/cache/restore-6.1.0
dependabot/npm_and_yarn/toon-format/toon-4.4.0
dependabot/github_actions/actions/deploy-pages-5.0.1
codex/review-fixes-pr-2403
codex/review-fixes-pr-2400
codex/process-terminal-width
codex/test-brittleness-cleanup
verify/7167-browser-connect-macos
fix/7167-browser-connect
feat/native-matching-allowance-setting
feat/browser-scenario-dry-run
test/managed-caller-parameters-20261024
codex/parser-fortythird-boundaries
fix/6926-pinvoke-platform-decorations-20261023
fix/6889-har-body-encoding-20261023
fix/6888-sqlite-schema-budget-20261023
fix/dependency-security-gates-6708
cursor/evidence-overwrite-rebase-b4ac
feat/4057-verify-native-exports
fix/windows-acl-observer-overhead-20261022
cursor/erlang-beam-restack-4476
cursor/pe-certificate-review-bf32
fix/6116-javascript-application-fs-errors
fix/6061-unmapped-runtime-script-unknown
feat/browser-scenario-summary
fix/pe-certificates
codex/verify-3407
cursor/rebase-5699
cursor/rebase-5352
cursor/rebase-5600
cursor/fix-cli-schema-omission-10a8
codex/audit-hopper-shutdown-reasons-20261021
fix/demangle-swift-omitted-record
fix/nib-boolean-value-types
cursor/cancellation-partial-observation-a5ac
fix/ib-object-limit-reasons
fix/electron-fuse-limit-advice
fix/kuna-doctor-dangling-cache
fix/fixed-budget-refusal-advice
fix/js-ipc-listener-dedup
fix/js-return-member-provenance
fix/dmg-integrity-retry-advice
fix/ida-doctor-readiness
fix/kuna-version-probe-output-drain
fix/legacy-swift-runtime-name-matching
fix/dylib-lazy-load-commands
fix/browser-scenario-startup-cancel
fix/swift-nested-punycode-classification
fix/compare-unselected-scopes
fix/objc-method-budget-coverage
fix/dmg-mounted-root-observations
audit/ci-tests-20261019-round2
release/6.7.0
fix/wabt-cleanup-retry-resolution
fix/electron-fuse-elf-pe-architecture
fix/native-plist-descriptor-ownership
fix/kuna-caller-cleanup-ownership
experiment/atomic-codemode-20261016
review/first-contributor-3776
fix/call-resolution-full-read-cycles
fix/member-mutation-selection-repeat
experiment/atomic-re-tools-20261015
perf/member-mutation-lazy-origins
perf/static-network-mutation-index
fix/hopper-startup-lifecycle
audit/3050-windows-proof-20261015
feat/windows-window-capture-2183
audit/3049-windows-proof-20261015
audit/3735-macos-fixtures-20261015
fix/batch-decompile-null-pseudocode
fix/kuna-inventory-honors-jobs
experiment/browser-codemode-tool-design-20261015
fix/hopper-clean-runtime-argv
codex/review-2049-27f1b367
review-fixes/pr-2787-routing
fix/3360-scoped-this-emitters
fix/3367-replaced-global-effects
fix/3838-compact-any-value-items
test/hopper-download-probe-20261015
codex/windows-runtime-creation-red-green-20261015
codex/windows-readonly-root-red-green-20261015
codex/windows-root-share-red-green-20261015
codex/exp-1685-win-mcp-startup
codex/bug-sweep-20261015
investigate/2190-windows-package-phases
investigate/3543-macos-cli-deadline
perf/3281-reverse-tools-feedback-quality
fix/3406-hopper-doctor-fixture
fix/3341-wrapper-require-test-context
fix/3301-owned-uninstall-fixtures
fix/3164-compiler-input-ownership
fix/pcap-cleanup-stdout-newline-20261014
perf/interface-builder-summary
codex/review-fixes-pr-1977
fix/ghidra-effective-jvm-platform
fix/docs-turkish-rust-link-20261013
fix/main-maintenance-ci-20261010
fix/recover-binary-session-process-effects
codex/review-fixes-pr-2457
codex/ci-required-cancellation-gate
fix/main-format-baseline-20261013
fix/setup-preserve-entry-fields
cursor/restore-main-checks-1ffc
fix/ghidra-bridge-hashmap-import
codex/shared-ci-jadx-json-default-20261013
codex/shared-ci-ghidra-test-groups-20261013
codex/shared-ci-java-fixture-format-20261013
codex/fix-intrinsic-invocation-boundaries
test/release-preflight-reusable-jobs
test/js-parameter-provenance-expectation
fix/linux-hopper-verification-current
test/2419-ghidra-elf-probe-size
followup/pr-1544-native-ida
codex/fold-pr-2230-contribution
docs/readme-responsible-use
fix/issue-2064
fix/issue-2050
fix/issue-2053
fix/issue-1968
fix/issue-1945
experiment/codemode-bridge-20261011
fix/tool-effects-negative-wording-1904-20261012
fix/1842-electron-interop-provenance
feat/recover-javascript-multi-input
refactor/website-i18n-prep
fix/nativeaot-pe-virtual-extent
fix/browser-verifier-ci-hang
fix/pe-resources-input-selection
docs/beginner-friendly-guides
docs/beginner-setup-guide
fix/javascript-analysis-worker-1563
fix/1649-ghidra-duplicate-names
fix/javascript-export-keys-integration-1369
test/maintenance-boundary-contracts-20261011
review/javascript-export-keys-1369
review/process-live-progress-1483
test/javascript-1495-growth-ratio
fix/ci-escape-timing
docs/normalized-terminal-geometry-1450
release/6.3.0
archive/release-6.3.0-pr1381
release/6.2.0
fix/electron-preload-dynamic-override
fix/javascript-self-referential-bundler-edges
release/6.1.0
cursor/grok-client-cherry-pick-0b56
feat/signature-posture
feat/dyld-shared-cache
feat/artifact-integrity-policy
feat/pkg-inventory
release/6.0.0
chore/sync-release-5.0.0
release/5.0.0
cursor/cloud-agent-node-787e
fix/javascript-xhr-open-endpoints
review/pr-711-realpath-fallback-wording
cleanup/replay-confinement
codex/test-suite-performance
codex/issue-foundations
codex/address-open-issues-2026-07-20
agent/javascript-vite-rollup-esbuild-adapters
agent/process-cleanup
agent/triage-integration
agent/unknown-commands-registry
feat/mcp-identity-metadata
morlvps/issue_cleanup
codex/installer-redesign
morl/roadmap-investigation-core
morl/roadmap-investigation-docs
release-please--branches--main--components--rea
rea-agents-6.8.0
rea-agents-6.7.0
rea-agents-6.6.0
experiment/atomic-codemode-wait-runtime-20261016
rea-agents-6.5.0
rea-agents-6.4.0
rea-agents-6.3.0
rea-agents-6.2.0
rea-agents-6.1.0
rea-agents-6.0.0
rea-agents-5.0.0
rea-agents-4.1.0
rea-agents-4.0.1
rea-agents-4.0.0
rea-agents-3.2.1
rea-agents-3.2.0
rea-agents-3.1.0
rea-agents-3.0.0
rea-agents-2.7.0
rea-agents-2.6.0
rea-agents-2.5.1
rea-agents-2.5.0
rea-agents-2.4.0
rea-agents-2.3.0
rea-agents-2.2.0
rea-agents-2.1.0
rea-agents-2.0.0
rea-agents-1.7.0
rea-agents-1.6.0
rea-agents-1.5.0
rea-agents-1.4.0
rea-agents-1.3.0
rea-agents-1.2.0
rea-agents-1.1.0
rea-agents-1.0.0
rea-agents-0.5.0
rea-agents-0.4.0
rea-agents-0.3.0
rea-0.2.1
rea-0.2.0
Labels
Clear labels
area: bridge
area: bridge
area: build
area: build
area: build
area: cli
area: domain
area: evidence
area: mcp
area: native
area: providers
area: runtime
area: server
area: setup
area: tests
bug
design
documentation
enhancement
enhancement
enhancement
experiment
help wanted
i18n
invalid
P0: critical
P1: high
P2: medium
P2: medium
P2: medium
P3: low
performance
provider-request
pull-request
Mirrored from GitHub Pull Request
question
roadmap
triage
No labels
area: bridge
area: bridge
area: build
area: build
area: build
area: cli
area: domain
area: evidence
area: mcp
area: native
area: providers
area: runtime
area: server
area: setup
area: tests
bug
design
documentation
enhancement
enhancement
enhancement
experiment
help wanted
i18n
invalid
P0: critical
P1: high
P2: medium
P2: medium
P2: medium
P3: low
performance
provider-request
pull-request
question
roadmap
triage
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
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#6517
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @morluto on GitHub (Oct 31, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8277
Originally assigned to: @kaoru0822-kitauji on GitHub.
Before submitting
Area
Native analysis or decompilation
Observed behavior
For a computed call through a writable pointer,
trace_call_pathwith Ghidra returnedgoal_status: "not_reached",relationship_coverage.status: "complete", and no residual unknowns for a function absent from Ghidra's resolved reference graph. Another function in the same fixture writes that function's address into the pointer before a subsequent call through it. The negative result therefore only describes the provider's recorded graph; it cannot rule out other targets of the computed call.Reproduction
I built a small x86-64 ELF with an initially populated writable function pointer and these functions (abbreviated from the tested assembly):
With Ghidra 12.1.4 through MCP,
resolve_native_call_targetsat the call inchange_then_callreturnedoverwritten_targetas a staticresolved-indirectprovider reference. At the call ininitial_only_callit returnedinitially_selectedas the provider reference.trace_call_path({start: "initial_only_call", goal: "overwritten_target"})returnednot_reached, complete relationship coverage and no residual unknown. The separatesequencedisassembly and pseudocode show the calls in the displayed order. Under the stated straight-line, single-threaded scenario, the instructions indicate that the second call uses the value written by the first; this is static reasoning, not a runtime observation. The target was never executed or changed.Control: REA/Kuna 1.986 returned
unknownwith partial callee coverage for both computed-call functions; its typed call-target operation was unavailable. Direct Kuna xrefs described the call as targeting the pointer slot, not a resolved function. LLVM disassembly independently confirmed the instructions and symbol addresses.Real-provider check of the proposed fix. On macOS arm64 with Ghidra 12.1.4 and JDK 21, I compared REA baseline
ae8223ccdfa0d5dbc659ddcbb7d6acf360343c3fwith contributor PR #8340 headb7e0b28083d3885ee80d3e23fee66c6ba03ef2ddthrough real stdio MCP using both compact and full schemas. The source-owned x86-64 ELF contains a writable function-pointer slot, a function that writes another target to it, a subsequent indirect caller, and a separate unresolved register call. The target was not executed and its SHA-256 remained60152582c3d599b9a6923d7ac7138887b6e5ab9f40114735c88980429cfe70e5.Ghidra's own analysis recorded a
COMPUTED_CALLreference from0x20117ato0x201159; no reference was injected in this check. On the baseline,procedure_calleesreported that edge with complete coverage, and the path to0x20115fwasnot_reachedwith no residual unknown. On #8340, the same edge remained, coverage became partial with the call-site address, and the path becameunknownwith a residual explaining the incomplete target set. A separate unresolved-register-call control remained unknown on both, and a no-call function remained a complete negative. Successful outputs validated against each advertised output schema.This is one fixture and host, not verification of IDA or every computed-call form; the import-slot control below is limited to two fixtures; the separate reverse-traversal check follows below. The baseline is a separate unmerged REA branch, not the PR's direct parent. PR #8340 is currently reported as conflicting with main; this check does not resolve its merge or scope questions.
Reverse-traversal control. On the same unexecuted fixture and real Ghidra,
procedure_callers(overwritten_target)returned the observed caller0x201165withcompletecoverage in both profiles. At #8340 headb7e0b280, backwardtrace_call_pathfromoverwritten_targettoinitial_only_callreturnednot_reachedand no residual unknown, while the forward path wasunknown. This leaves the issue's mutable-slot alternative unqualified in the backward direction. A backward positive frominitially_selectedtoinitial_only_callstayedreached.On separate PR #8443 head
ef5a7e68, the same backward negative becameunknownwithsearch_scope.discovery: unknownandobserved_goal_status: not_reached; the positive stayedreached. The underlyingprocedure_callersresult still reported complete coverage. These are separate, unmerged branches, not a combined fix. All successful replies validated against the advertised compact/full schemas; the target SHA-256 remained unchanged. The result does not measure how often computed targets occur or decide whether a whole-program scan is warranted.Import-call tradeoff control. Using real Ghidra 12.1.4 via both compact and full stdio MCP profiles, I compared #8340 head
b7e0b280with separate baselineae8223cc. In a source-owned ARM64 Mach-O, the function loads_mallocthrough its GOT and calls withblr x16at0x1368. Ghidra reported one computed-call reference to0xc000. The PR retained that edge and changedprocedure_calleescoverage from complete to partial. In a separate x86-64 ELF with an interposable defined function andR_X86_64_JUMP_SLOTrelocation, the caller directly calls its PLT stub at0x1013b0; its callee coverage remained complete. Both results validated against the advertised schemas.This demonstrates the PR's import-slot cost for one computed call and a contrasting direct-to-stub call; it does not establish prevalence, runtime binding, or justify assuming GOT calls have fixed targets. Neither target was executed or changed: SHA-256 values were
62da83d290c7b276d8708937930ef12f469f41782710fed439001c01c2747c76and741f17c72cea92c0316549c9733cdf77c528d890fde6231bdf4cc8ba325aa630respectively. Cross-library evidence and interposition are separately discussed in #8221.Expected behavior
Distinguish a completed traversal of the provider-observed graph from evidence that computed-call targets are exhaustive. Preserve the observed reference and static graph result, but expose residual target uncertainty in a negative answer when it has not been established. This need not imply runtime execution or require an unconditional whole-program data-flow analysis. A machine-direct call with genuinely complete observed adjacency is a useful positive control.
Impact and scope
An agent can read the definite negative and complete relationship status as ruling out a path that the fixture's cross-function state flow permits. The output also has general limitations about unresolved indirect calls, and
resolve_native_call_targetscorrectly warns its reference is static; the issue is that a reported target suppresses remaining computed-target uncertainty in the path result. No real agent behavior or runtime execution was measured. One fixture, one host and two provider versions were exercised.REA version
Runtime reproduction at
e6d0618979f0df3f1d5db218b0fc7b5e6a9cf3f9. Source at main22e5aa97af8d726400f3f932cae10e0083412038retains the same relevant logic; its runtime was not retested.Runtime and platform
Node 24.22.1, macOS arm64, Ghidra 12.1.4, Kuna 1.986, JDK 21.
Target and artifact context
Self-built x86-64 ELF; static analysis only.
Interface
MCP
Earliest failure stage
Native analysis or reconstruction
Relevant output or evidence
Ghidra call at
0x20117a: target reference0x201159(initially_selected); selected goal0x20115f(overwritten_target); path resultnot_reached,truncated: false,residual_unknowns: []. The instruction at0x20116cwrites0x20115finto the same slot read at0x20117a;sequencecalls the writer before the reader.xrefson the slot exposed both sites. Aresolved-indirectreference is expressly described as static and not proof of execution.Typed outcome or recovery expected
A graph-only negative and a possibly incomplete computed-target set should remain separately machine-readable, so the caller can preserve the unknown without discarding known edges.
Analysis or suspected cause
Source-derived:
callRelationshipCoveragestarts at complete and marks missing targets when a decoded call has no reported call reference or a reported reference is missing from the callee inventory. A computed call with one reference need not trigger that condition.CallPathTracingprojectsnot_reachedwhen there is no path and no residual unknown. This explains the observed result without establishing Ghidra's internal reasoning for the specific reference.Additional context
Related #8200 concerns call-site/type visibility; #3988 concerns missing IDA relationship coverage. This report is about the completeness and negative-path interpretation of an existing Ghidra computed reference. Suggested checks include the mutable cross-function case, a direct call, unresolved and multiple candidate sites, reverse traversal, and real MCP plus CLI; those checks have not all been run.
cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
@morluto commented on GitHub (Oct 31, 2026):
Looping in @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0 for visibility on the Ghidra, Kuna, and REA tool-design investigation.
@morluto commented on GitHub (Oct 31, 2026):
Reverse and direct-call controls on the same fixture, same real providers through MCP:
reachedfor the directsequence -> change_then_calledge, andnot_reachedfor_start(a return-only function) tooverwritten_target. This is a narrow control, not a guarantee of complete graph discovery in other binaries.overwritten_targettoinitial_only_call, Ghidra returnednot_reached, complete coverage at every visited node, and no residual unknowns. Itsprocedure_callers(overwritten_target)returned onlychange_then_call, the caller with a reported computed reference. The same fixture'ssequencefirst writesoverwritten_targetinto the slot and then callsinitial_only_call, as described above. That is an instruction-based possibility, not an observed execution.unknownwith partial caller coverage and stated that unresolved indirect calls elsewhere in the image could add callers. Its backward directinitial_only_call -> sequencequery still returnedreachedwhile retaining partial coverage. Ghidra also reached that known direct caller.Reverse absence has a different scope from forward expansion: a possible unreported indirect caller need not appear among already visited callers. Any correction should preserve known edges and the ability to report a completed provider-observed graph, while keeping the scope of the negative explicit; the control does not dictate a global scan or claim exhaustive runtime targets. The target digest stayed unchanged and the target was not executed.
@morluto commented on GitHub (Oct 31, 2026):
Independent architecture/format control on current main
b43c329df779708e43ae297f498a844e45d9c923: I compiled an unexecuted arm64 Mach-O where a volatile function pointer starts at_audit_initial;_audit_select_alternatestores_audit_alternate; and_audit_sequencecalls that setter before_audit_dispatch, which loads the pointer and performsblr.Real REA/Ghidra 12.1.4 MCP classified the dispatch call's reference to the initial target as
resolved-indirect. A forward path from_audit_dispatchto_audit_alternateand a backward path from_audit_alternateto_audit_dispatchboth returnednot_reached, complete observed relationship coverage and no residual unknowns. Independent LLVM disassembly showed the prior store and subsequent indirect call; as in the original report, their sequential effect is a static inference, not an observed execution. Both REA providers reached the direct_audit_sequence -> _audit_dispatchcontrol. REA/Kuna 1.986 returnedunknownwith partial relationship coverage for both indirect-path queries.This reproduces the graph-scope distinction on a second format/architecture, not a proof about all Ghidra inputs. The target digest was unchanged. Current main was built with
build:cached; this check used MCP only.@morluto commented on GitHub (Oct 31, 2026):
I exercised the same arm64 mutable-pointer fixture through other REA workflows on
b43c329df779708e43ae297f498a844e45d9c923with real Ghidra 12.1.4 and Kuna 1.986 over MCP:analyze_functionfor_audit_dispatchretained the initial target as a callee, an emptyunresolved_callslist, andrelationship_coverage.status: completewith the diagnostic that only resolved references are returned.get_call_graphcarried the same candidate and complete relationship status on that node. Those are provider-graph observations; the setter/sequence from the earlier control means they do not establish an exhaustive set of possible values in the writable slot.trace_native_valuesreturned aresolved-indirectedge to the initial target and preserved its source Evidence, with general limitations that alias dependencies remain unknown and a static reference is not proof of execution. Its specific unknown in this run was a missing argument binding; it did not separately enumerate the alternate pointer value.trace_native_ui_action, seeded by the native function (not an actual UI action), preserved the indirect call site and candidate, markedstatic_native_callspartial, and explicitly warned that a resolved static edge does not establish runtime reachability. Its cross-function value-flow facet was unsupported. This is a useful existing uncertainty presentation even though it does not resolve the mutable slot.The target digest stayed unchanged and the binary was not executed. This is one scripted native seed and fixture, not a UI or autonomous-agent evaluation. It suggests the fix should consider the shared relationship/completeness owner and its consumers, rather than changing only the final
trace_call_pathwording or dropping the known candidate.@morluto commented on GitHub (Oct 31, 2026):
Test and offline-composition follow-up
The existing test suite does exercise a real Ghidra indirect call:
verifyUnresolvedCallEvidenceinscripts/lib/native-value-e2e.mjschecks a callback passed as a function parameter through real stdio MCP and expects partial relationships and an unknown path. The fixture has no resolved candidate for that call. It does not cover the different shape above, where Ghidra reports one computed-call candidate while another value can be written to the slot.The separate
callPathSearchExtentMcp.test.tsconstructs Evidence with explicit unresolved calls and checks that the consumer preserves them. That is useful coverage of the handoff, but it cannot detect a real provider reporting the relationship as complete in the first place.With the same real Ghidra fixture and two complete dossiers, a separate actual
build_call_pathprobe returnedfoundfor the initial candidate andnot_foundwithsearch_scope.exhaustive: truefor the alternate when the MCP input allowance was raised. That is the result for the supplied observed graph; it does not prove runtime reachability or unreachability. The generic provider limitations were also returned. Under the default allowance, both two-dossier requests stopped at the input limit instead; the separate composition issue is #8281.Proposed regression: a real-provider E2E should cover a computed call with both an observed candidate and an independently evidenced writable alternative, checking that the candidate remains available while the unproven negative retains appropriate uncertainty through live paths and offline composition. The fixture was analyzed statically and not executed.
@morluto commented on GitHub (Oct 31, 2026):
Cross-target comparison and structural verification
I built two source-owned arm64 Mach-O fixtures with the same writable function-pointer initializer and identical dispatcher/sequence instructions. The setter in one stores
audit_initial; the setter in the other storesaudit_alternate. LLVM disassembly confirms the setter's materialized function address differs and the sequence calls the setter before the dispatcher. This is a static, straight-line interpretation; neither binary was executed.On REA
b43c329df779708e43ae297f498a844e45d9c923with Ghidra 12.1.4, I analyzed each target through stdio MCP, exported each Evidence bundle beforeclose_binary, imported both bundles, and compared retained dossiers:_audit_initialas the sole callee, no unresolved calls, and complete relationship coverage.compare_functionsreported the dispatcher's calls asunchanged, carrying a generic indirect-call limitation; its overall status wasunknownfor a separate reference-identity limitation.verify_reconstructionstructural-function claim for dispatchercallspassed; anoverallclaim was unknown, so the combined result was unknown. The passing claim retained generic provider caveats and is a comparison of supplied structural observations, not proof of behavior or a claim of whole-program equivalence.find_changed_behaviorretained these as four static candidates and returned behavior unknown. Comparing the unchanged sequence also returned behavior unknown.This shows the effect of candidate-only coverage can extend to a downstream structural claim, even when the broader comparison remains unknown. A regression for the producing boundary should check this handoff as well, while continuing to preserve the observed candidate and distinguish local structure from runtime or cross-function effects. Both target SHA-256 digests remained unchanged.
@morluto commented on GitHub (Oct 31, 2026):
A correction to the proposed validation above: the tested REA
b43c329CLI does not advertisetrace_call_pathorbuild_call_path;rea traceis the separate literal-feature workflow. The directly applicable end-to-end path regression is therefore public stdio MCP, not an assumed CLI command. This is a statement about the tested CLI, not a proposal to add an API-parity wrapper.A related real CLI observation is available: on the previously reported arm64 writable-pointer fixture,
rea resolve-native-call-targets <fixture> 0x1000003f4 --provider ghidra --format json --full-outputsucceeded withmechanism: computed,status: resolved-indirect, and one staticprovider-referencecandidate. Its limitations correctly say that a resolved reference is not proof of execution. The fixture's SHA-256 remainedf771508a5d2a8afee3419ad1a075c6f4ad499fbb91b2584f49c9c006fb908e05; the target was not executed. This separate call-site observation is not a CLI reproduction of the path result. The inspected CLI and relevant path/bridge source files are unchanged betweenb43c329and the localorigin/mainchecked today.@morluto commented on GitHub (Oct 31, 2026):
Follow-up on the same ELF with REA
b43c329, Ghidra 12.1.4 and Kuna 1.986 over real MCP:analyze_function(initial_only_call, detail=complete)returnedinitially_selectedas a callee, an emptyunresolved_callslist, and top-level relationship coveragecompletewith the general resolved-reference diagnostic.get_call_graphreturned the same candidate and marked that node's relationship coverage complete. This extends the reported coverage concern beyondtrace_call_path.trace_native_ui_actionpreserved theindirect_calledge as resolved, but its overallstatic_native_callscoverage was explicitlypartial; it also described cross-function value flow as unsupported and warned that the edge does not prove runtime reachability. This is a useful existing contrast, not an assertion that it recovers the other target.The separately tested Kuna ELF UI trace did not run because its dispatch preflight failed; its discovery mismatch is reported in #8322. This follow-up does not establish runtime dispatch or all composed-tool behavior.
@morluto commented on GitHub (Oct 31, 2026):
Current-main follow-up after #8299 fixed retained dossier inputs: on
a989c0e458c91af177e097abd7be0fd021b0401d, a fresh target-free MCP server imported a bundle from a real Ghidra session on the earlier arm64 writable-slot fixture. With the default input allowance and two retained dossier references,build_call_pathstill returnedstatus: not_found,search_scope.exhaustive: truefor the alternate function, with both source links and the provider's general limitations. The original observed-candidate path succeeded, and both offline operations used the same imported source Evidence. The target was not opened in the offline server and the bundle hash was unchanged. This is an exhaustive statement about the supplied observed graph, not proof that computed runtime targets are exhaustive; the composition fix and this coverage question are separate.@morluto commented on GitHub (Oct 31, 2026):
Retested the previously documented arm64 Mach-O mutable-slot fixture on current REA
c287a73276a7f751ca65a8cc2219a29d5914bc2c, Ghidra 12.1.4 and Kuna 1.986 through real stdio MCP. Ghidra still reports the initial target as a staticresolved-indirectprovider reference, and returnsnot_reached, complete reported relationship coverage and no residual unknowns for both forward and reverse paths to the alternate. Kuna reports unknown with partial relationship coverage in both directions. Both providers reached the direct-call control. The fixture's source and disassembly establish the static write/call scenario described earlier, not runtime execution; its SHA-256 was unchanged. This is a current-revision confirmation of the existing issue, not a new correctness or performance claim.@morluto commented on GitHub (Oct 31, 2026):
A real shipped-binary positive control for the existing uncertainty behavior: REA
2d5dec26c31662764c9adfe3ff996174901b8d49, macOS arm64, Ghidra 12.1.4 and Kuna 1.986, Homebrew Brotli 1.2.0libbrotlidec.1.2.0.dylibSHA-256d7ac1e69b6c443341fb4302de0169d187489d58d8a641c8eadd6db9ca2cd0cbf. Its installed public header describes optional allocator/free callbacks. Independentotoolshows register calls at0x12f8and0x1348in_BrotliDecoderCreateInstance, and a direct call to_BrotliDecoderStateInitat0x1320.Ghidra
resolve_native_call_targetsreports the two callback sites unresolved and the direct site direct. Both Ghidra and Kunatrace_call_pathreach_BrotliDecoderStateInitwhile preserving partial callee coverage; an unrelated_BrotliDecoderVersiongoal returnsunknownrather than a definite negative.get_call_graphsummaries likewise retain partial coverage at the entry. Ghidratrace_native_valuesidentifies both callback sites as unresolved; Kuna reports its unavailable native def-use model explicitly. These are static results, not runtime observations. The library and installed header hashes remained unchanged; neither was executed. Successful MCP responses were validated by the SDK against the compact advertised schemas. My initialget_call_graphrequest incorrectly supplieddepth; the reported graph is from the corrected separate call.This is the unresolved-target case behaving conservatively; it does not resolve the candidate-plus-writable-alternate issue reported here. The same shipped sample also reproduces Kuna's unrelated self-data-xref issue: Noelo-Lab/kuna#1334.
@morluto commented on GitHub (Oct 31, 2026):
I tested one deliberately conservative local experiment, not a proposed complete fix, against real Ghidra 12.1.4 and REA
60149282fcfc05ac32fbc94434c107710120da6f. In an isolated worktree,callBoundaryObservationadditionally counted decoded computed calls that already had a ReferenceManager call destination;callRelationshipCoveragethen marked callee coverage partial for those sites while preserving the reported callees. No other production source was changed.On the existing unexecuted mutable-pointer arm64 Mach-O:
not_reachedwith complete coverage; the experiment returnedunknownwith a computed-target-set limitation.reachedwith partial coverage. A direct-call positive and a return-only leaf negative kept their prior reached/not-reached results and complete coverage.get_call_graphboth retained the known callee and propagated partial coverage. A graph view exported and imported into a fresh target-free server was identical to the live view.not_reachedwith complete caller coverage. A per-function outgoing check cannot establish completeness of incoming references from other functions; this experiment does not solve reverse traversal.On the previously tested PE import-through-IAT control, the known external path remained reached but changed from complete to partial, because that call is decoded as computed. This illustrates the cost of blanket conservatism; how to distinguish a bounded import target from an incomplete set needs a typed basis, not an assumption based on names or raw bytes. On the shipped Brotli unresolved-callback control, the direct path remained reached with partial coverage and an unrelated goal remained unknown.
All successful calls used the SDK's compact advertised-schema validator; three static targets' hashes were unchanged and none was executed. The local patch was not submitted or merged. Remaining work includes reverse coverage, precise candidate/exhaustiveness semantics, other providers and architectures, cancellation/resource implications of any image-wide analysis, and meaningful real CLI/MCP regression coverage. This experiment does not establish those properties.
@morluto commented on GitHub (Nov 1, 2026):
Native Ghidra reference and PE permission controls
I used Ghidra 12.1.4
analyzeHeadlesswith a read-only script against the source-owned x86-64 ELF and PE fixtures. At the ELF writable-pointer call (0x20117a), Ghidra reported aREADreference to writable.data/mutable_slotand anANALYSISCOMPUTED_CALLreference to the internalinitially_selectedfunction. At the PE import call (0x14000100c), it reported aREADreference to.rdataand anANALYSISCOMPUTED_CALLreference to externalAUDIT.DLL::audit_transform.For a controlled counterexample to treating external imports or section permissions as interchangeable, I made an owned PE copy with only the
.rdatawritable section-characteristic bit changed (one byte in the file). Ghidra still reported the same external symbol and reference types, but its memory block changed from non-writable to writable. This is an intentionally modified static fixture, not evidence about a naturally occurring executable or runtime loader behavior.On REA
025272ee2a9763a3f174a9dba7a8eda8fc722cf3with real Ghidra and stdio MCP,resolve_native_call_targetsandinspect_native_instructionreturned identical normalized call-site observations for both PE files. The latter exposed both the slotREADreference and the external computed-call reference;inspect_native_load_imageseparately reported.rdata.writable: falseversustrue. The section contents' observed SHA-256 matched. Both files' full hashes remained unchanged during REA analysis; neither was executed. Compact advertised schemas were used by the SDK.Ghidra documents
MemoryBlock.isWriteas the write property of its program memory block, andReference.getSourceas the reference's source. These facts are useful static provenance; neither independently proves an exhaustive runtime target set. In particular, a rule that assumes an external target has a non-writable slot is not valid for this fixture. Conversely, this case does not prove that a writable slot is actually changed or that a read-only slot cannot change at runtime. The existing REA tools can expose the relevant observations without introducing another provider wrapper; whether a bounded path workflow should surface or join them remains a design question related to #8200 and #8340.