[PR #2470] [MERGED] fix(ghidra): pre-create the launch-support config directory #5253

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2470
Author: @AbdulAzizWang
Created: 10/13/2026
Status: ✅ Merged
Merged: 10/13/2026
Merged by: @morluto

Base: main ← Head: fix/ghidra-windows-launch-config


📝 Commits (4)

  • c74d9cc fix(ghidra): pre-create the launch-support config directory
  • b86e8ab test(ghidra): cover Windows launch configuration directories
  • 0cbcd2f style(ghidra): format launch configuration regressions
  • 79f93f3 fix(ghidra): reuse Java Properties parsing for launch release identity

📊 Changes

2 files changed (+114 additions, -3 deletions)

View changed files

📝 src/ghidra/GhidraLauncher.ts (+48 -2)
📝 tests/boundary/providers/ghidra/ghidraLauncher.test.ts (+66 -1)

📄 Description

Problem

On Windows x64 the first Ghidra-backed query fails even though rea doctor reports a valid
Ghidra installation and 64-bit JDK. Ghidra's launch support cannot persist its JDK choice
inside REA's private runtime:

java.io.IOException: Failed to create directory:
...\config\ghidra\ghidra_12.1.4_PUBLIC
    at ghidra.launch.AppConfig.saveJavaHome(AppConfig.java:145)
    at LaunchSupport.findJavaHome(LaunchSupport.java:210)

LaunchSupport then falls back to its interactive prompt, reads EOF, and prints
JDK 21+ (64-bit) could not be found and must be manually chosen!, so the provider fails
with Ghidra exited before bridge startup.

Cause

createGhidraRuntimeDirectories creates the six runtime roots but not the launch-support
release directory Ghidra writes into. The private runtime's DACL lets the owning process
write, but the launched JVM does not create those directories itself, so saveJavaHome
throws and JDK resolution aborts.

Fix

Create <config>/ghidra/<release directory> before launch, one level at a time, while this
process still owns the runtime, so Ghidra only has to write a file inside it. The release
coordinate comes from the installation's Ghidra/application.properties
(application.version plus application.release.name), with the extraction directory name
as a fallback.

Validation

Windows x64, Ghidra 12.1.4, 64-bit Temurin JDK 21, REA's packaged native addon:

  • rea inspect <x64 PE DLL> --provider ghidra --format json completes and reports 21
    segments, 1436 procedures, and 2761 strings.
  • The equivalent MCP binary_overview call returns the same Evidence record.

rea doctor --provider ghidra was already healthy before this change, so the failure was
only observable on the first real Ghidra query.

Reproduction

Observed on: Windows 10+ x64, Node.js 24.15.0, Ghidra 12.1.4 (official zip), 64-bit Temurin
JDK 21.0.12.1, native addon from the packaged artifact. TEMP/TMP were left at their
defaults.

  1. Build the parent commit with the pinned toolchain (npm ci && npm run build:cached) and
    export absolute paths:

    $env:GHIDRA_INSTALL_DIR = "C:\tools\ghidra_12.1.4_PUBLIC"
    $env:JAVA_HOME          = "C:\tools\jdk-21"
    
  2. Confirm the installation itself is accepted. This is healthy both before and after the
    change, which is why the failure looked unrelated to setup:

    rea doctor --provider ghidra --json
    # ghidra-java             -> 21.0.12.1; 64-bit; JDK; accepted
    # ghidra-native_authority -> verified
    
  3. Run the first Ghidra-backed query on any native x64 PE (EXE or DLL), using the documented
    entry point from docs/windows-ghidra-p0.md:

    rea inspect "C:\fixtures\sample.exe" --provider ghidra --format json
    
  4. Result: execution_failure, failure_kind: "process",
    failure_message: "Ghidra exited before bridge startup". The retained diagnostics carry
    the cause. stdout:

    ******************************************************************
    JDK 21+ (64-bit) could not be found and must be manually chosen!
    ******************************************************************
    Enter path to JDK home directory (ENTER for dialog):
    ERROR: Failed to find a supported JDK.
    

    stderr:

    java.io.IOException: Failed to create directory:
      <runtime>\config\ghidra\ghidra_12.1.4_PUBLIC
        at ghidra.launch.AppConfig.saveJavaHome(AppConfig.java:145)
        at LaunchSupport.findJavaHome(LaunchSupport.java:210)
        at LaunchSupport.handleJavaHome(LaunchSupport.java:153)
        at LaunchSupport.main(LaunchSupport.java:113)
    java.lang.NullPointerException: Cannot invoke "String.trim()" because the return value
    of "java.io.BufferedReader.readLine()" is null
        at LaunchSupport.askJavaHome(LaunchSupport.java:300)
        at LaunchSupport.handleJavaHome(LaunchSupport.java:151)
    

    The askJavaHome NPE is LaunchSupport falling back to its interactive prompt after the
    saveJavaHome IOException; there is no console, so it reads EOF and reports that no
    supported JDK was found.

  5. After this change the same command completes and open_binary / binary_overview return
    analysis Evidence. Ghidra's launch support now resolves the JDK from JAVA_HOME and
    writes java_home.save into the pre-created directory itself:

    <runtime>\config\ghidra\ghidra_12.1.4_PUBLIC\java_home.save
    

The same launch path is exercised by npm run verify:ghidra:windows.

Notes for review

  • The report is Windows-specific; I have not tested other hosts, where the runtime roots are
    created with plain mkdir rather than the native private-runtime owner.
  • If the intended contract is that the launched JVM should be able to create that directory
    itself, a pointer to where that is enforced would be welcome — pre-creating it is the
    minimal change that unblocked the P0 path here.
  • Adjacent to #2010, which made this diagnosable by retaining LaunchSupport output.

🔄 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/2470 **Author:** [@AbdulAzizWang](https://github.com/AbdulAzizWang) **Created:** 10/13/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/ghidra-windows-launch-config` --- ### 📝 Commits (4) - [`c74d9cc`](https://github.com/morluto/rea/commit/c74d9cca72f428f25e98ed971ebf1a0716b7ddc1) fix(ghidra): pre-create the launch-support config directory - [`b86e8ab`](https://github.com/morluto/rea/commit/b86e8ab87e43acb932bc5b1dffc685271aa00e3e) test(ghidra): cover Windows launch configuration directories - [`0cbcd2f`](https://github.com/morluto/rea/commit/0cbcd2f16146b91979daf9a5890bb4eb32074e59) style(ghidra): format launch configuration regressions - [`79f93f3`](https://github.com/morluto/rea/commit/79f93f3fd8894110c91eff9a30dd8f76367ad360) fix(ghidra): reuse Java Properties parsing for launch release identity ### 📊 Changes **2 files changed** (+114 additions, -3 deletions) <details> <summary>View changed files</summary> 📝 `src/ghidra/GhidraLauncher.ts` (+48 -2) 📝 `tests/boundary/providers/ghidra/ghidraLauncher.test.ts` (+66 -1) </details> ### 📄 Description ## Problem On Windows x64 the first Ghidra-backed query fails even though `rea doctor` reports a valid Ghidra installation and 64-bit JDK. Ghidra's launch support cannot persist its JDK choice inside REA's private runtime: ``` java.io.IOException: Failed to create directory: ...\config\ghidra\ghidra_12.1.4_PUBLIC at ghidra.launch.AppConfig.saveJavaHome(AppConfig.java:145) at LaunchSupport.findJavaHome(LaunchSupport.java:210) ``` LaunchSupport then falls back to its interactive prompt, reads EOF, and prints `JDK 21+ (64-bit) could not be found and must be manually chosen!`, so the provider fails with `Ghidra exited before bridge startup`. ## Cause `createGhidraRuntimeDirectories` creates the six runtime roots but not the launch-support release directory Ghidra writes into. The private runtime's DACL lets the owning process write, but the launched JVM does not create those directories itself, so `saveJavaHome` throws and JDK resolution aborts. ## Fix Create `<config>/ghidra/<release directory>` before launch, one level at a time, while this process still owns the runtime, so Ghidra only has to write a file inside it. The release coordinate comes from the installation's `Ghidra/application.properties` (`application.version` plus `application.release.name`), with the extraction directory name as a fallback. ## Validation Windows x64, Ghidra 12.1.4, 64-bit Temurin JDK 21, REA's packaged native addon: - `rea inspect <x64 PE DLL> --provider ghidra --format json` completes and reports 21 segments, 1436 procedures, and 2761 strings. - The equivalent MCP `binary_overview` call returns the same Evidence record. `rea doctor --provider ghidra` was already healthy before this change, so the failure was only observable on the first real Ghidra query. ## Reproduction Observed on: Windows 10+ x64, Node.js 24.15.0, Ghidra 12.1.4 (official zip), 64-bit Temurin JDK 21.0.12.1, native addon from the packaged artifact. `TEMP`/`TMP` were left at their defaults. 1. Build the parent commit with the pinned toolchain (`npm ci && npm run build:cached`) and export absolute paths: ```powershell $env:GHIDRA_INSTALL_DIR = "C:\tools\ghidra_12.1.4_PUBLIC" $env:JAVA_HOME = "C:\tools\jdk-21" ``` 2. Confirm the installation itself is accepted. This is healthy both before and after the change, which is why the failure looked unrelated to setup: ```powershell rea doctor --provider ghidra --json # ghidra-java -> 21.0.12.1; 64-bit; JDK; accepted # ghidra-native_authority -> verified ``` 3. Run the first Ghidra-backed query on any native x64 PE (EXE or DLL), using the documented entry point from `docs/windows-ghidra-p0.md`: ```powershell rea inspect "C:\fixtures\sample.exe" --provider ghidra --format json ``` 4. Result: `execution_failure`, `failure_kind: "process"`, `failure_message: "Ghidra exited before bridge startup"`. The retained diagnostics carry the cause. stdout: ``` ****************************************************************** JDK 21+ (64-bit) could not be found and must be manually chosen! ****************************************************************** Enter path to JDK home directory (ENTER for dialog): ERROR: Failed to find a supported JDK. ``` stderr: ``` java.io.IOException: Failed to create directory: <runtime>\config\ghidra\ghidra_12.1.4_PUBLIC at ghidra.launch.AppConfig.saveJavaHome(AppConfig.java:145) at LaunchSupport.findJavaHome(LaunchSupport.java:210) at LaunchSupport.handleJavaHome(LaunchSupport.java:153) at LaunchSupport.main(LaunchSupport.java:113) java.lang.NullPointerException: Cannot invoke "String.trim()" because the return value of "java.io.BufferedReader.readLine()" is null at LaunchSupport.askJavaHome(LaunchSupport.java:300) at LaunchSupport.handleJavaHome(LaunchSupport.java:151) ``` The `askJavaHome` NPE is LaunchSupport falling back to its interactive prompt after the `saveJavaHome` IOException; there is no console, so it reads EOF and reports that no supported JDK was found. 5. After this change the same command completes and `open_binary` / `binary_overview` return analysis Evidence. Ghidra's launch support now resolves the JDK from `JAVA_HOME` and writes `java_home.save` into the pre-created directory itself: ``` <runtime>\config\ghidra\ghidra_12.1.4_PUBLIC\java_home.save ``` The same launch path is exercised by `npm run verify:ghidra:windows`. ## Notes for review - The report is Windows-specific; I have not tested other hosts, where the runtime roots are created with plain `mkdir` rather than the native private-runtime owner. - If the intended contract is that the launched JVM should be able to create that directory itself, a pointer to where that is enforced would be welcome — pre-creating it is the minimal change that unblocked the P0 path here. - Adjacent to #2010, which made this diagnosable by retaining LaunchSupport output. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:05:10 +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#5253
No description provided.