[GH-ISSUE #8085] [Bug] A repeated rea decompile with the same --snapshot runs Ghidra again instead of replaying #4669

Closed
opened 2026-10-31 00:52:15 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @Entrpi on GitHub (Oct 30, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8085

Before submitting

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

Area

CLI

Observed behavior

A repeated rea decompile --procedure main with the same --snapshot takes as long as the first run, although the snapshot holds the first run's Evidence. A repeated rea analyze replays from the same snapshot in under a second.

Query (same snapshot file) Run 1 Run 2 Run 3
rea decompile hello --procedure main --provider ghidra 7.70 s 7.59 s 7.65 s
rea analyze hello --provider ghidra 7.61 s 0.86 s —

All decompile runs return the same evidence_id, and so do both analyze runs.

Reproduction

Ran once; each command was repeated as shown in the table.

printf 'int add(int a, int b) { return a + b; }\nint main(int argc, char **argv) { return add(argc, 2); }\n' > hello.c
clang -O1 -g -o hello hello.c
rea decompile "$PWD/hello" --procedure main --provider ghidra --snapshot "$PWD/snap.json" --json > d1.json
rea decompile "$PWD/hello" --procedure main --provider ghidra --snapshot "$PWD/snap.json" --json > d2.json
rea analyze "$PWD/hello" --provider ghidra --snapshot "$PWD/snap.json" --json > a1.json
rea analyze "$PWD/hello" --provider ghidra --snapshot "$PWD/snap.json" --json > a2.json

Expected behavior

The second decompile replays the saved result, as the second analyze does. docs/cli.md, "Save and reuse analysis snapshots": "REA reuses an exact result when the target bytes, operation, parameters, provider and settings match", and "An exact CLI cache hit is normally read before starting a provider process."

Impact and scope

Each repeated decompile pays the full Ghidra start-up and analysis again. On this 17 KB test binary that is about 7 s per query; on firmware-sized images it is the whole analysis time. Results stay correct. Only decompile with --procedure was tested; other operations were not.

REA version

Source revision 317bf3fe2 (main, 30 Oct 2026), built with npm run build:cached.

Runtime and platform

Node.js 24.22.1; Debian GNU/Linux 13 (trixie), x86_64, in an LXC container; Ghidra 12.1.4 PUBLIC; OpenJDK 21.

Target and artifact context

x86-64 ELF executable (PIE, ET_DYN, with DWARF), 17,064 bytes, built by Debian clang 19.1.7 from the two-function source above.

Interface

CLI

Earliest failure stage

Unknown

Relevant output or evidence

Wall-clock times from bash time. After the four queries, snap.json (63,659 bytes) contains the decompile entry: the operation appears in its entries and the first run's evidence_id in its Evidence bundle. The decompile Evidence records only parameters: {"procedure": "main"}.

Typed outcome or recovery expected

A cache hit, as for analyze, without starting Ghidra.

Analysis or suspected cause

Not established. Hypothesis, not checked against the source: the CLI resolves a --procedure name through the provider before it looks for an exact cache hit, so the provider starts even when the snapshot holds the result. Decompiling by address was not tested.

Additional context

NOT_ENOUGH_INFO for a last known good version: this was first noticed on 28 Oct with a fork build of an ESP-IDF Xtensa app (--procedure app_main), and reproduced here on main.

Current Ghidra document and source controls

On REA d7df9df33 plus the unrelated draft #8867, real Ghidra 12.1.4/JDK 21 on macOS arm64 was exercised through stdio MCP in both schema profiles. For a fresh imported program, repeated procedure_pseudo_code without document did not report replay and produced no snapshot entry for that request. Selecting the actual list_documents result caused the second call to replay; its snapshot entry also replayed after reopening. The one-shot decompile CLI does not advertise a document selector. These are separate controls from the original Linux CLI timing and do not establish a new end-to-end timing.

Source inspection shows document-scoped calls without a document are excluded by isSourceEvidenceRetainable / isSnapshotCacheable; this is a different mechanism from the original issue's hypothesis that name resolution starts the provider before lookup. A saved-project control with a synthetic historical source did not replay even with an explicit document because its source-bearing execution is excluded by a separate fail-closed rule; see #8869. The owned target and saved project's descriptor hashes were unchanged.

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Originally created by @Entrpi on GitHub (Oct 30, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8085 ### 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 CLI ### Observed behavior A repeated `rea decompile --procedure main` with the same `--snapshot` takes as long as the first run, although the snapshot holds the first run's Evidence. A repeated `rea analyze` replays from the same snapshot in under a second. | Query (same snapshot file) | Run 1 | Run 2 | Run 3 | | --- | --- | --- | --- | | `rea decompile hello --procedure main --provider ghidra` | 7.70 s | 7.59 s | 7.65 s | | `rea analyze hello --provider ghidra` | 7.61 s | 0.86 s | — | All decompile runs return the same `evidence_id`, and so do both analyze runs. ### Reproduction Ran once; each command was repeated as shown in the table. ```bash printf 'int add(int a, int b) { return a + b; }\nint main(int argc, char **argv) { return add(argc, 2); }\n' > hello.c clang -O1 -g -o hello hello.c rea decompile "$PWD/hello" --procedure main --provider ghidra --snapshot "$PWD/snap.json" --json > d1.json rea decompile "$PWD/hello" --procedure main --provider ghidra --snapshot "$PWD/snap.json" --json > d2.json rea analyze "$PWD/hello" --provider ghidra --snapshot "$PWD/snap.json" --json > a1.json rea analyze "$PWD/hello" --provider ghidra --snapshot "$PWD/snap.json" --json > a2.json ``` ### Expected behavior The second `decompile` replays the saved result, as the second `analyze` does. `docs/cli.md`, "Save and reuse analysis snapshots": "REA reuses an exact result when the target bytes, operation, parameters, provider and settings match", and "An exact CLI cache hit is normally read before starting a provider process." ### Impact and scope Each repeated decompile pays the full Ghidra start-up and analysis again. On this 17 KB test binary that is about 7 s per query; on firmware-sized images it is the whole analysis time. Results stay correct. Only `decompile` with `--procedure` was tested; other operations were not. ### REA version Source revision `317bf3fe2` (`main`, 30 Oct 2026), built with `npm run build:cached`. ### Runtime and platform Node.js 24.22.1; Debian GNU/Linux 13 (trixie), x86_64, in an LXC container; Ghidra 12.1.4 PUBLIC; OpenJDK 21. ### Target and artifact context x86-64 ELF executable (PIE, `ET_DYN`, with DWARF), 17,064 bytes, built by Debian clang 19.1.7 from the two-function source above. ### Interface CLI ### Earliest failure stage Unknown ### Relevant output or evidence Wall-clock times from bash `time`. After the four queries, `snap.json` (63,659 bytes) contains the decompile entry: the operation appears in its `entries` and the first run's `evidence_id` in its Evidence bundle. The decompile Evidence records only `parameters: {"procedure": "main"}`. ### Typed outcome or recovery expected A cache hit, as for `analyze`, without starting Ghidra. ### Analysis or suspected cause Not established. Hypothesis, not checked against the source: the CLI resolves a `--procedure` name through the provider before it looks for an exact cache hit, so the provider starts even when the snapshot holds the result. Decompiling by address was not tested. ### Additional context NOT_ENOUGH_INFO for a last known good version: this was first noticed on 28 Oct with a fork build of an ESP-IDF Xtensa app (`--procedure app_main`), and reproduced here on `main`. ### Current Ghidra document and source controls On REA `d7df9df33` plus the unrelated draft #8867, real Ghidra 12.1.4/JDK 21 on macOS arm64 was exercised through stdio MCP in both schema profiles. For a fresh imported program, repeated `procedure_pseudo_code` without `document` did not report replay and produced no snapshot entry for that request. Selecting the actual `list_documents` result caused the second call to replay; its snapshot entry also replayed after reopening. The one-shot `decompile` CLI does not advertise a document selector. These are separate controls from the original Linux CLI timing and do not establish a new end-to-end timing. Source inspection shows document-scoped calls without a document are excluded by `isSourceEvidenceRetainable` / `isSnapshotCacheable`; this is a different mechanism from the original issue's hypothesis that name resolution starts the provider before lookup. A saved-project control with a synthetic historical source did not replay even with an explicit document because its source-bearing execution is excluded by a separate fail-closed rule; see #8869. The owned target and saved project's descriptor hashes were unchanged. cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
Author
Owner

@xu91102 commented on GitHub (Oct 30, 2026):

I reproduced this on fresh main 317bf3fe235e655b2d752d3be261cc0da7d00f2b before making any product changes, using the real compiled public CLI, official Ghidra 12.1.4 (native decompiler built from the same release for macOS arm64), JDK 21, and an owned two-function Mach-O compiled with clang -O1 -g. The target was analyzed, never executed.

With the same target, _main selector and snapshot, the first/repeated decompile calls both exited 0, returned the same Evidence ID, and each started a Java provider process: 10.39 s / 10.24 s. analyze on the same snapshot was a positive control: 12.16 s initially / 3.26 s repeated, with no observed Java process on the replay. These are local wall times, not a general performance guarantee or model-token measurement.

The saved snapshot contains the procedure_pseudo_code Evidence with {procedure: "_main"}, but no corresponding provider or workflow cache entry; the binary_overview control has its workflow entry. Source tracing points to documentless provider-cache admission rather than a failed decompilation. A one-shot CLI target binding needs to be distinguished from a persistent session's implicit document, while preserving ordinary session/export retention bounds, exact target/profile/selector matching, live-result exclusions, and Windows native-source admission.

I checked the actual relevant production changes in #2025/#3531/#1948/#7486: companion/profile identity, persistent Ghidra project storage, and target-language admission respectively, rather than this missing exact one-shot result binding. I have not run their heads. No fix has been implemented yet; the baseline outputs, snapshot, target digest and process-observation records are retained locally.

Update: the fix is now published as Draft #8089 at f4a622c2b1833a1ae286159b9cc8f02be8990a6d (base 317bf3fe). The shared snapshot owner admits only the exact explicit one-shot Ghidra pseudocode context; persistent implicit-document and export policies remain unchanged. Real same-input controls now replay identical Evidence without observed Java startup, with legacy migration and target/selector refusal controls preserved. Final focused/README validation is 172 distinct passes and 2 existing Windows skips; check/docs/discovery/package/pack and frozen independent Standards/Spec reviews pass. Dedicated installed-package Ghidra, Windows/Linux Ghidra and full agent/model workflows are not run. Upstream CI is separate and still being followed. Human readiness declarations remain unchecked on the Draft. No issue-close or foreign-PR mutation was made.

<!-- gh-comment-id:6513954433 --> @xu91102 commented on GitHub (Oct 30, 2026): I reproduced this on fresh main `317bf3fe235e655b2d752d3be261cc0da7d00f2b` before making any product changes, using the real compiled public CLI, official Ghidra 12.1.4 (native decompiler built from the same release for macOS arm64), JDK 21, and an owned two-function Mach-O compiled with `clang -O1 -g`. The target was analyzed, never executed. With the same target, `_main` selector and snapshot, the first/repeated `decompile` calls both exited 0, returned the same Evidence ID, and each started a Java provider process: 10.39 s / 10.24 s. `analyze` on the same snapshot was a positive control: 12.16 s initially / 3.26 s repeated, with no observed Java process on the replay. These are local wall times, not a general performance guarantee or model-token measurement. The saved snapshot contains the `procedure_pseudo_code` Evidence with `{procedure: "_main"}`, but no corresponding provider or workflow cache entry; the `binary_overview` control has its workflow entry. Source tracing points to documentless provider-cache admission rather than a failed decompilation. A one-shot CLI target binding needs to be distinguished from a persistent session's implicit document, while preserving ordinary session/export retention bounds, exact target/profile/selector matching, live-result exclusions, and Windows native-source admission. I checked the actual relevant production changes in #2025/#3531/#1948/#7486: companion/profile identity, persistent Ghidra project storage, and target-language admission respectively, rather than this missing exact one-shot result binding. I have not run their heads. No fix has been implemented yet; the baseline outputs, snapshot, target digest and process-observation records are retained locally. Update: the fix is now published as Draft #8089 at `f4a622c2b1833a1ae286159b9cc8f02be8990a6d` (base `317bf3fe`). The shared snapshot owner admits only the exact explicit one-shot Ghidra pseudocode context; persistent implicit-document and export policies remain unchanged. Real same-input controls now replay identical Evidence without observed Java startup, with legacy migration and target/selector refusal controls preserved. Final focused/README validation is 172 distinct passes and 2 existing Windows skips; check/docs/discovery/package/pack and frozen independent Standards/Spec reviews pass. Dedicated installed-package Ghidra, Windows/Linux Ghidra and full agent/model workflows are not run. Upstream CI is separate and still being followed. Human readiness declarations remain unchecked on the Draft. No issue-close or foreign-PR mutation was made.
Author
Owner

@bonro commented on GitHub (Oct 30, 2026):

We offer the full series of GPT models at 0.2x official pricing and the full series of Claude models at 0.3x official pricing, available now at lanmu1313.top.

<!-- gh-comment-id:6515733711 --> @bonro commented on GitHub (Oct 30, 2026): We offer the full series of GPT models at 0.2x official pricing and the full series of Claude models at 0.3x official pricing, available now at lanmu1313.top.
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#4669
No description provided.