[GH-ISSUE #5576] [Bug] analyze_swift_types counts Objective-C labels containing _Tt as Swift observations #3389

Closed
opened 2026-10-31 00:39:50 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 20, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5576

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

With the Hopper provider, analyze_swift_types {} and analyze_swift_types {"category":"other"} both return two Swift observations for an Objective-C fixture whose selector contains _Tt. The only retained names are -[Widget _TtReset] and _objc_msgSend$_TtReset, each with only itself in mangled_names. Both enter other and unclassified with category_not_decoded. Renaming the selector to TtReset returns zero observations for both requests.

An independent verifier reproduced this through the built checkout's supported MCP stdio entry point, then successfully reran the public recipe. No Swift source was compiled into either fixture.

Reproduction

  1. From the built source revision below, with the local Hopper provider available, create this fixture in a disposable working directory:
#import <Foundation/Foundation.h>
@interface Widget : NSObject
- (void)_TtReset;
- (void)resetAll;
@end
@implementation Widget
- (void)_TtReset { }
- (void)resetAll { }
@end
int main(void) {
    Widget *w = [[Widget alloc] init];
    [w _TtReset];
    [w resetAll];
    return 0;
}
  1. Save it as widget.m, build it, and build the selector-renamed control:
clang -fobjc-arc -framework Foundation widget.m -o widget
sed 's/_TtReset/TtReset/g' widget.m > control.m
clang -fobjc-arc -framework Foundation control.m -o control
  1. Connect an MCP stdio client to node scripts/rea.mjs mcp from the built checkout. The verified recipe used isolated temporary HOME, XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_CACHE_HOME, XDG_STATE_HOME, and TMPDIR directories, with inherited REA_, HOPPER_, and GHIDRA_ variables removed.
  2. Call open_binary with {"path":"<absolute path to widget>","provider_id":"hopper"}. Call analyze_swift_types with {}, then {"category":"other"}. Inspect normalized_result in the returned evidence. Call close_binary with {}.
  3. Repeat those calls for control, opening only one target at a time. The original fixture returns two observations; the control returns zero.
  4. Call binary_session with {}. In the verified runs both closes succeeded and the final state was open: false, cleanup_pending: false.

The verifier ran this workflow and repeated it successfully using the final public recipe. These executables were analyzed without executing them or saving a Hopper database.

Expected behavior

For this fixture, return total: 0, zero category counts, and unclassified: [], as for the selector control. An Objective-C method label or message-send shim does not become a Swift name because its selector contains _Tt.

The expectation is grounded in src/contracts/enhancedToolContracts.ts:54-56 (also confirmed through MCP tools/list), which describes Swift manglings or same-address Swift aliases, and src/domain/symbolAnalysis.ts:156-157, which describes procedure-name count semantics. Genuine Swift observations with undecoded categories must remain available in other and unclassified.

Impact and scope

The tested valid Objective-C input produces false Swift inventory entries and incorrect procedure-name counts. This is a bounded P2 impact assessment; other providers and ordinary-binary prevalence were not measured. No target bytes changed.

For this fixture, callers can manually inspect the retained names against the Objective-C symbols and exclude these two confirmed false positives. Discarding all other or unclassified results would also lose legitimate unresolved Swift evidence and is not a safe general workaround.

REA version

6.7.0, built from source commit 074768901f3cdc8205b61773fb1faf6f6c7b3ca8.

Runtime and platform

Node.js v26.12.0; macOS 27.0.1 build 26A434, arm64; Apple clang 21.0.0 (clang-2100.3.34.2); Hopper Disassembler 6.1.0-demo build 42.6295552. Observations concern this installed demo copy; a licensed distribution was not independently tested.

Target and artifact context

Self-built arm64 Mach-O Objective-C executable and selector-renamed control, linked against Foundation, libobjc, and libSystem. No Swift source was compiled into either fixture.

Interface

MCP

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The independent verifier observed this projection from both unfiltered and other-filtered MCP responses for widget:

{
  "total": 2,
  "other_count": 2,
  "other_items": [
    {
      "address": "0x100000818",
      "name": "-[Widget _TtReset]",
      "mangled_names": ["-[Widget _TtReset]"]
    },
    {
      "address": "0x1000008c0",
      "name": "_objc_msgSend$_TtReset",
      "mangled_names": ["_objc_msgSend$_TtReset"]
    }
  ],
  "unclassified_names": ["-[Widget _TtReset]", "_objc_msgSend$_TtReset"],
  "unclassified_reasons": ["category_not_decoded", "category_not_decoded"]
}

This projection flattens categories.other.count, categories.other.items, and corresponding unclassified entries. All five other category counts were zero. Addresses depend on compiler/build. The selector control returned total: 0, all counts zero, and unclassified: [] for both requests. xcrun nm independently confirmed the Objective-C labels.

The existing npm run test:local -- src/domain/symbolAnalysis.test.ts passed all 16 tests; that run used Node.js v24.22.0. Supplementary built-domain controls retained $s4_TtX4PairVMa and __T04main4PairVMa as structs and $e4main7ServiceCMa as unresolved Swift evidence. Those controls were internal probes, not additional real-Hopper reproductions.

Typed outcome or recovery expected

Return an empty Swift inventory for both Objective-C fixtures. Preserve genuine modern and legacy Swift observations, including a modern mangling whose identifier contains _Tt, and genuine Swift observations whose categories cannot be decoded. Dropping the entire unresolved bucket would not restore the contract.

Analysis or suspected cause

Source-derived reasoning: src/domain/swiftSymbolClassification.ts:26-33 accepts non-modern names containing _Tt anywhere and returns a null category for these Objective-C labels. src/domain/symbolAnalysis.ts:69-70,105-142 accepts and counts them. The supported MCP handler in src/server/registerEnhancedTools.ts:130-139 reaches the inventory retrieval in src/application/EnhancedTools.ts:559-592.

The submitter fetched current upstream main at 8443692e2bd93f31eae8bc0e018544abc4ed71e9. The cited classifier, aggregation, contract, and application files are unchanged from the reproduction baseline; the registration-file change only affects workflow snapshot recording. No later source change in these paths plausibly fixes this behavior. No new Hopper session was run for submission.

Additional context

Prepared with AI assistance and independently reproduced by a separate verifier.

Related but different: #5553 concerns genuine Swift nested Unicode types inheriting their enclosing type's category and disappearing under a class filter. This report concerns non-Swift Objective-C labels entering the inventory at all. Either defect can remain after the other is fixed. #4296 / PR #4319 concern substituted extension contexts; closed #3934 / merged PR #4085 concern alias category voting; closed #1187 / merged PR #1208 concern missing modern Swift observations. None reports this false inclusion.

Regression range: NOT_ENOUGH_INFO; no last-known-good version was established.

Originally created by @coygeek on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5576 ### 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 With the Hopper provider, `analyze_swift_types {}` and `analyze_swift_types {"category":"other"}` both return two Swift observations for an Objective-C fixture whose selector contains `_Tt`. The only retained names are `-[Widget _TtReset]` and `_objc_msgSend$_TtReset`, each with only itself in `mangled_names`. Both enter `other` and `unclassified` with `category_not_decoded`. Renaming the selector to `TtReset` returns zero observations for both requests. An independent verifier reproduced this through the built checkout's supported MCP stdio entry point, then successfully reran the public recipe. No Swift source was compiled into either fixture. ### Reproduction 1. From the built source revision below, with the local Hopper provider available, create this fixture in a disposable working directory: ```objc #import <Foundation/Foundation.h> @interface Widget : NSObject - (void)_TtReset; - (void)resetAll; @end @implementation Widget - (void)_TtReset { } - (void)resetAll { } @end int main(void) { Widget *w = [[Widget alloc] init]; [w _TtReset]; [w resetAll]; return 0; } ``` 2. Save it as `widget.m`, build it, and build the selector-renamed control: ```sh clang -fobjc-arc -framework Foundation widget.m -o widget sed 's/_TtReset/TtReset/g' widget.m > control.m clang -fobjc-arc -framework Foundation control.m -o control ``` 3. Connect an MCP stdio client to `node scripts/rea.mjs mcp` from the built checkout. The verified recipe used isolated temporary HOME, XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_CACHE_HOME, XDG_STATE_HOME, and TMPDIR directories, with inherited REA_, HOPPER_, and GHIDRA_ variables removed. 4. Call `open_binary` with `{"path":"<absolute path to widget>","provider_id":"hopper"}`. Call `analyze_swift_types` with `{}`, then `{"category":"other"}`. Inspect `normalized_result` in the returned evidence. Call `close_binary` with `{}`. 5. Repeat those calls for `control`, opening only one target at a time. The original fixture returns two observations; the control returns zero. 6. Call `binary_session` with `{}`. In the verified runs both closes succeeded and the final state was `open: false`, `cleanup_pending: false`. The verifier ran this workflow and repeated it successfully using the final public recipe. These executables were analyzed without executing them or saving a Hopper database. ### Expected behavior For this fixture, return `total: 0`, zero category counts, and `unclassified: []`, as for the selector control. An Objective-C method label or message-send shim does not become a Swift name because its selector contains `_Tt`. The expectation is grounded in `src/contracts/enhancedToolContracts.ts:54-56` (also confirmed through MCP `tools/list`), which describes Swift manglings or same-address Swift aliases, and `src/domain/symbolAnalysis.ts:156-157`, which describes procedure-name count semantics. Genuine Swift observations with undecoded categories must remain available in `other` and `unclassified`. ### Impact and scope The tested valid Objective-C input produces false Swift inventory entries and incorrect procedure-name counts. This is a bounded P2 impact assessment; other providers and ordinary-binary prevalence were not measured. No target bytes changed. For this fixture, callers can manually inspect the retained names against the Objective-C symbols and exclude these two confirmed false positives. Discarding all `other` or `unclassified` results would also lose legitimate unresolved Swift evidence and is not a safe general workaround. ### REA version 6.7.0, built from source commit `074768901f3cdc8205b61773fb1faf6f6c7b3ca8`. ### Runtime and platform Node.js v26.12.0; macOS 27.0.1 build 26A434, arm64; Apple clang 21.0.0 (clang-2100.3.34.2); Hopper Disassembler 6.1.0-demo build 42.6295552. Observations concern this installed demo copy; a licensed distribution was not independently tested. ### Target and artifact context Self-built arm64 Mach-O Objective-C executable and selector-renamed control, linked against Foundation, libobjc, and libSystem. No Swift source was compiled into either fixture. ### Interface MCP ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The independent verifier observed this projection from both unfiltered and `other`-filtered MCP responses for `widget`: ```json { "total": 2, "other_count": 2, "other_items": [ { "address": "0x100000818", "name": "-[Widget _TtReset]", "mangled_names": ["-[Widget _TtReset]"] }, { "address": "0x1000008c0", "name": "_objc_msgSend$_TtReset", "mangled_names": ["_objc_msgSend$_TtReset"] } ], "unclassified_names": ["-[Widget _TtReset]", "_objc_msgSend$_TtReset"], "unclassified_reasons": ["category_not_decoded", "category_not_decoded"] } ``` This projection flattens `categories.other.count`, `categories.other.items`, and corresponding `unclassified` entries. All five other category counts were zero. Addresses depend on compiler/build. The selector control returned `total: 0`, all counts zero, and `unclassified: []` for both requests. `xcrun nm` independently confirmed the Objective-C labels. The existing `npm run test:local -- src/domain/symbolAnalysis.test.ts` passed all 16 tests; that run used Node.js v24.22.0. Supplementary built-domain controls retained `$s4_TtX4PairVMa` and `__T04main4PairVMa` as structs and `$e4main7ServiceCMa` as unresolved Swift evidence. Those controls were internal probes, not additional real-Hopper reproductions. ### Typed outcome or recovery expected Return an empty Swift inventory for both Objective-C fixtures. Preserve genuine modern and legacy Swift observations, including a modern mangling whose identifier contains `_Tt`, and genuine Swift observations whose categories cannot be decoded. Dropping the entire unresolved bucket would not restore the contract. ### Analysis or suspected cause Source-derived reasoning: `src/domain/swiftSymbolClassification.ts:26-33` accepts non-modern names containing `_Tt` anywhere and returns a null category for these Objective-C labels. `src/domain/symbolAnalysis.ts:69-70,105-142` accepts and counts them. The supported MCP handler in `src/server/registerEnhancedTools.ts:130-139` reaches the inventory retrieval in `src/application/EnhancedTools.ts:559-592`. The submitter fetched current upstream main at `8443692e2bd93f31eae8bc0e018544abc4ed71e9`. The cited classifier, aggregation, contract, and application files are unchanged from the reproduction baseline; the registration-file change only affects workflow snapshot recording. No later source change in these paths plausibly fixes this behavior. No new Hopper session was run for submission. ### Additional context Prepared with AI assistance and independently reproduced by a separate verifier. Related but different: #5553 concerns genuine Swift nested Unicode types inheriting their enclosing type's category and disappearing under a class filter. This report concerns non-Swift Objective-C labels entering the inventory at all. Either defect can remain after the other is fixed. #4296 / PR #4319 concern substituted extension contexts; closed #3934 / merged PR #4085 concern alias category voting; closed #1187 / merged PR #1208 concern missing modern Swift observations. None reports this false inclusion. Regression range: NOT_ENOUGH_INFO; no last-known-good version was established.
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#3389
No description provided.