Skip to content

Harden Ghidra remote server shutdown#200

Open
amattas wants to merge 1 commit into
binsync:mainfrom
amattas:pr/ghidra-remote-server-shutdown
Open

Harden Ghidra remote server shutdown#200
amattas wants to merge 1 commit into
binsync:mainfrom
amattas:pr/ghidra-remote-server-shutdown

Conversation

@amattas

@amattas amattas commented Jun 15, 2026

Copy link
Copy Markdown

Problem

BinSync's Ghidra integration runs a declib DecompilerServer inside Ghidra and talks to it from a separate UI process. Two lifecycle issues make failures hard to diagnose and can crash or strand Ghidra:

  • GUI-backed Ghidra APIs are not safe to call concurrently from arbitrary socket worker threads, but declib did not mark the Ghidra backend as requiring main-thread dispatch. That means remote UI requests could enter Ghidra from worker threads instead of the thread that owns the Ghidra program context.
  • DecompilerClient.shutdown_server() sent shutdown_deci, which tears down the decompiler interface but does not ask the server loop itself to stop. The server already has a shutdown_server handler for that, but the client was not using it.

Together, these make the Ghidra remote path fragile: errors can leave the server running, and backend calls can execute on unsafe threads.

Solution

  • Mark GUI-backed GhidraDecompilerInterface instances as requiring DecompilerServer main-thread dispatch.
  • Keep headless Ghidra direct by clearing that flag for headless=True instances.
  • Change DecompilerClient.shutdown_server() to send the server's real shutdown_server request before disconnecting.
  • Add focused tests for the shutdown request type and the Ghidra dispatch flag.

Verification

  • PYTEST_ADDOPTS='-p no:cacheprovider' conda run -n ghidra python -m pytest tests/test_client_server.py::TestClientServer::test_shutdown_server_requests_server_stop tests/test_ghidra_server_dispatch.py -q -> 2 passed
  • PYTHONPYCACHEPREFIX=/tmp/declib-pyc conda run -n ghidra python -m compileall -q declib tests
  • git diff --check

Dependency

The BinSync Ghidra lifecycle PR depends on this declib change for the full fix: BinSync can wait on main-thread-dispatch servers and ask the remote server to stop, but declib must expose that Ghidra requires main-thread dispatch and must route shutdown_server() to the server stop handler.

Notes

The broader declib Ghidra integration suite was not used for this PR because this local checkout is missing the external /Users/amattas/GitHub/bs-artifacts/binaries/fauxware fixture. The focused unit tests cover the behavior changed here without requiring that binary.

@mahaloz

mahaloz commented Jun 25, 2026

Copy link
Copy Markdown
Member

Hi @amattas thanks for contributing to BinSync. Since I am noticing the same pattern across all your PRs, would you be able to reduce the number of new testcase files you introduce? I am see that in every PR you introduce a new file, when, instead, many could just be single functions added to already existent test. You likley used AI here, and that is fine, just try to reduce the number of new things you create in the project.

This also refers to your other BinSync PRs:
binsync/binsync#528

Could you ping me when you reduce them a little?

@amattas

amattas commented Jun 25, 2026

Copy link
Copy Markdown
Author

Yes, I was trying to keep the changes atomic, but I can roll of them up into one change if you prefer that approach.

@mahaloz

mahaloz commented Jun 25, 2026

Copy link
Copy Markdown
Member

Yeah adding to the existing testcase files would be ideal whenever applicable :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants