[GH-ISSUE #1649] [Bug] Ghidra set_address_name accepts a duplicate name and returns true #556

Closed
opened 2026-10-15 18:26:08 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @CassieFox23 on GitHub (Oct 10, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1649

TL;DR: With Ghidra, set_address_name lets two functions take the same name and returns true both times. The #1635 text says a duplicate returns false. The Hopper contract also rejects a name that another address owns. So the two providers differ, and a caller can't trust true to mean the name is unique.

Before submitting

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

Area

Native analysis or decompilation

Observed behavior

On main at 0f605bca9 (#1602), which includes 6e0d5d64d (#1635), with the Ghidra provider:

Call Result
set_address_name 0x400466 → dup_name (function add_one) true
set_address_name 0x40047a → dup_name (function add_two) true
set_address_name 0x40300c → dup_label (global) true
set_address_name 0x403010 → dup_label (global) true

list_names then shows both addresses as primary dup_name functions, and both as primary dup_label labels. The decompiled main calls dup_name twice:

  iVar1 = dup_name(param_1);
  iVar2 = dup_name(param_1);

Reproduction

  1. Build this with gcc -O0 on x86-64 Linux:
#include <stdio.h>

int g_counter = 5;
int g_other = 9;

__attribute__((noinline)) int add_one(int v) { return v + g_counter; }
__attribute__((noinline)) int add_two(int v) { return v + g_other + 2; }
__attribute__((noinline)) int add_three(int v) { return v * 3 + g_counter; }

int main(int argc, char **argv) {
  (void)argv;
  printf("%d\n", add_one(argc) + add_two(argc) + add_three(argc));
  return 0;
}
  1. Start rea mcp with REA_ANALYSIS_PROVIDER=ghidra. Call open_binary with provider_id: "ghidra".
  2. Call set_address_name on the add_one entry with dup_name, then on the add_two entry with dup_name. My addresses were 0x400466 and 0x40047a; yours depend on the build.
  3. Call list_names, and procedure_pseudo_code on main.

Expected behavior

Three places point the other way:

An invalid or duplicate name, or a readback mismatch, returns false and rolls back only that address.

That is the #1635 description.

the same compact naming results as Hopper

That is docs/native-investigation.md, on the Ghidra tools.

rejects names owned by another address

That is the set_address_name contract, on Hopper.

So I expected the second call to return false and leave add_two unchanged.

Impact and scope

An agent that names helpers in bulk can give two functions one name without any sign. Later reads by name are then ambiguous. I saw this in the global namespace only. I did not test Hopper or IDA.

REA version

main 0f605bca9 (#1602), built from source. Not in a release yet.

Runtime and platform

Nobara 44 (Fedora 44 base), Linux 7.2.9, x86-64. Node 24.18.0. Ghidra 12.1.4 (Apache-2.0) with JDK 21.0.12.1.

Target and artifact context

The small program above, built with gcc 16.2.1, not stripped, x86-64 ELF.

Interface

MCP

Earliest failure stage

Native analysis or reconstruction

Typed outcome or recovery expected

false for the second address, with the first name kept. Or, if Ghidra allows this on purpose, the docs and the #1635 text should say so.

I found this while checking #1635 on Linux. My notes are in my comment there.

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

Originally created by @CassieFox23 on GitHub (Oct 10, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1649 **TL;DR:** With Ghidra, `set_address_name` lets two functions take the same name and returns `true` both times. The #1635 text says a duplicate returns `false`. The Hopper contract also rejects a name that another address owns. So the two providers differ, and a caller can't trust `true` to mean the name is unique. ### 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 Native analysis or decompilation ### Observed behavior On main at 0f605bca9 (#1602), which includes 6e0d5d64d (#1635), with the Ghidra provider: | Call | Result | |---|---| | `set_address_name` 0x400466 → `dup_name` (function `add_one`) | `true` | | `set_address_name` 0x40047a → `dup_name` (function `add_two`) | `true` | | `set_address_name` 0x40300c → `dup_label` (global) | `true` | | `set_address_name` 0x403010 → `dup_label` (global) | `true` | `list_names` then shows both addresses as primary `dup_name` functions, and both as primary `dup_label` labels. The decompiled `main` calls `dup_name` twice: ```c iVar1 = dup_name(param_1); iVar2 = dup_name(param_1); ``` ### Reproduction 1. Build this with `gcc -O0` on x86-64 Linux: ```c #include <stdio.h> int g_counter = 5; int g_other = 9; __attribute__((noinline)) int add_one(int v) { return v + g_counter; } __attribute__((noinline)) int add_two(int v) { return v + g_other + 2; } __attribute__((noinline)) int add_three(int v) { return v * 3 + g_counter; } int main(int argc, char **argv) { (void)argv; printf("%d\n", add_one(argc) + add_two(argc) + add_three(argc)); return 0; } ``` 2. Start `rea mcp` with `REA_ANALYSIS_PROVIDER=ghidra`. Call `open_binary` with `provider_id: "ghidra"`. 3. Call `set_address_name` on the `add_one` entry with `dup_name`, then on the `add_two` entry with `dup_name`. My addresses were 0x400466 and 0x40047a; yours depend on the build. 4. Call `list_names`, and `procedure_pseudo_code` on `main`. ### Expected behavior Three places point the other way: > An invalid or duplicate name, or a readback mismatch, returns `false` and rolls back only that address. That is the #1635 description. > the same compact naming results as Hopper That is `docs/native-investigation.md`, on the Ghidra tools. > rejects names owned by another address That is the `set_address_name` contract, on Hopper. So I expected the second call to return `false` and leave `add_two` unchanged. ### Impact and scope An agent that names helpers in bulk can give two functions one name without any sign. Later reads by name are then ambiguous. I saw this in the global namespace only. I did not test Hopper or IDA. ### REA version main 0f605bca9 (#1602), built from source. Not in a release yet. ### Runtime and platform Nobara 44 (Fedora 44 base), Linux 7.2.9, x86-64. Node 24.18.0. Ghidra 12.1.4 ([Apache-2.0](https://github.com/NationalSecurityAgency/ghidra/blob/master/LICENSE)) with JDK 21.0.12.1. ### Target and artifact context The small program above, built with gcc 16.2.1, not stripped, x86-64 ELF. ### Interface MCP ### Earliest failure stage Native analysis or reconstruction ### Typed outcome or recovery expected `false` for the second address, with the first name kept. Or, if Ghidra allows this on purpose, the docs and the #1635 text should say so. I found this while checking #1635 on Linux. My notes are in [my comment there](https://github.com/morluto/rea/pull/1635#issuecomment-6102956891). 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
Author
Owner

@N0zoM1z0 commented on GitHub (Oct 10, 2026):

Reproduced on current Linux main with real Ghidra 12.1.4/JDK 21 through REA stdio MCP: both duplicate function names and duplicate data labels returned true; the rejection regression failed, and owned-process cleanup completed. A provider-boundary fix now rejects another address owning the name in the same namespace while preserving same-address replay and separate namespaces. The small real MCP reproduction passes after the fix; the host-native Ghidra lane is running with batch and annotation rollback regressions. No Hopper/IDA or native macOS/Windows claim.

<!-- gh-comment-id:6103246610 --> @N0zoM1z0 commented on GitHub (Oct 10, 2026): Reproduced on current Linux main with real Ghidra 12.1.4/JDK 21 through REA stdio MCP: both duplicate function names and duplicate data labels returned `true`; the rejection regression failed, and owned-process cleanup completed. A provider-boundary fix now rejects another address owning the name in the same namespace while preserving same-address replay and separate namespaces. The small real MCP reproduction passes after the fix; the host-native Ghidra lane is running with batch and annotation rollback regressions. No Hopper/IDA or native macOS/Windows claim.
Author
Owner

@N0zoM1z0 commented on GitHub (Oct 10, 2026):

Independently confirmed the landed fix on Linux at main 26038912 (including aa7c5b7b) with actual Ghidra 12.1.4/JDK 21 and public REA stdio MCP: duplicate function/data names are rejected, old names survive, and same-address replay succeeds. Additional mapped-interior-label and imported-external-symbol collision controls pass; public CLI annotation still preserves the existing native naming behavior. Target bytes remained unchanged and owned-process lineage was verified empty. My overlapping PR #1652 was closed without merging. The earlier full Linux lane passed on that separate PR source, not this main revision; this comment claims the focused landed-main controls only.

<!-- gh-comment-id:6103468409 --> @N0zoM1z0 commented on GitHub (Oct 10, 2026): Independently confirmed the landed fix on Linux at main `26038912` (including `aa7c5b7b`) with actual Ghidra 12.1.4/JDK 21 and public REA stdio MCP: duplicate function/data names are rejected, old names survive, and same-address replay succeeds. Additional mapped-interior-label and imported-external-symbol collision controls pass; public CLI annotation still preserves the existing native naming behavior. Target bytes remained unchanged and owned-process lineage was verified empty. My overlapping PR #1652 was closed without merging. The earlier full Linux lane passed on that separate PR source, not this main revision; this comment claims the focused landed-main controls only.
Author
Owner

@CassieFox23 commented on GitHub (Oct 10, 2026):

Thanks, morluto, for the fix in aa7c5b7b5. Thanks, N0zoM1z0, for confirming it on Linux with the extra collision cases.

🤖 Generated with Claude Code (Opus 5.5) 🦊

<!-- gh-comment-id:6103485734 --> @CassieFox23 commented on GitHub (Oct 10, 2026): Thanks, morluto, for the fix in aa7c5b7b5. Thanks, N0zoM1z0, for confirming it on Linux with the extra collision cases. 🤖 Generated with Claude Code (Opus 5.5) 🦊
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#556
No description provided.