[GH-ISSUE #8201] [Bug] Electron graph reports 0 IPC channels and 0 BrowserWindows on a real Rolldown bundle (Signal Desktop 8.33.0) #6482

Open
opened 2026-11-01 21:11:31 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

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

Area

Evidence, artifacts, or reconstruction

Interface

MCP, CLI

Earliest failure stage

Native analysis or reconstruction

Observed behavior

analyze_javascript_application on Signal Desktop 8.33.0 (Electron 44.9.1, arm64, open source AGPL-3.0) returns ipc.operations = 0 and browser_windows = 0 for bundles/main.js (662 KB). The result only carries generic partial/unknown flags. There is no specific warning that Electron semantic recovery came back empty, so it reads as "this app uses no IPC".

As a consequence, trace_application_feature with a channel seed and with a string seed (SignalClipboard) both return no-match, although the feature exists and is traceable by hand (renderer → preload ipcRenderer.send('SignalClipboard.copyTextTemporarily', ...) → main ipcMain.on(...)).

Raising the semantic limit to 1,000,000 (CLI, 45 s, 215 MB JSON) still returns 0.

Reproduction

  1. Install Signal Desktop 8.33.0 for macOS arm64 and extract app.asar.
  2. Run analyze-javascript-application on the extracted directory, scoped to package.json and bundles/main.js.
  3. Read the Electron view: ipc.operations and browser_windows.
  4. Compare with a text count on the same file: ipcMain.handle|on|once and new BrowserWindow.

Expected behavior

Most of the 101 ipcMain channels (52 handle, 45 on, 8 once) and the 9 BrowserWindow constructions are recovered. The public source app/main.main.ts at tag v8.33.0 declares 66 channels; 65 of them are present in the bundle. If recovery fails, the result should say that Electron semantic coverage is empty or degraded, rather than reporting 0.

Impact and scope

Silent false negative on a widely used Electron app. Feature tracing and version comparison (compare_application_versions) depend on this graph, so they also return nothing useful.

Relevant evidence

  • We could not reproduce it on synthetic files. Single-quoted and backtick require('electron'), plus a simulated Rolldown prologue (c=e.o(c,1), f.ipcMain.handle(...)), are all detected correctly. The failure appears only on the real, large bundle.
  • Related but closed: #1656 (aliasing variables).
  • Also observed: a whole-ASAR run hit provider_timeout after 300 s on a 301 KB chunk (file 90 of 1086) and still wrote a 233 MB error JSON. The 6.5 MB preload bundle was not analysed within default limits.

Typed outcome or recovery expected

a coverage indicator for Electron semantics (for example electron_semantics: empty | degraded) when recovery yields nothing on a file that imports electron.

REA version, runtime and platform

REA: rea-agents 6.8.0 (npm)
Runtime: Node.js 24.22.1
Platform: macOS 27.2 (Darwin), arm64
Providers: Ghidra 12.1.4 (natives built locally with support/gradle buildNatives), OpenJDK 25.0.5, Hopper 6.6.0 demo
Client: Claude Code 2.1.309–2.1.314
Originally created by @xuanhieu on GitHub (Oct 30, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8201 ### 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 Evidence, artifacts, or reconstruction ### Interface MCP, CLI ### Earliest failure stage Native analysis or reconstruction ### Observed behavior `analyze_javascript_application` on Signal Desktop 8.33.0 (Electron 44.9.1, arm64, open source AGPL-3.0) returns `ipc.operations = 0` and `browser_windows = 0` for `bundles/main.js` (662 KB). The result only carries generic partial/unknown flags. There is no specific warning that Electron semantic recovery came back empty, so it reads as "this app uses no IPC". As a consequence, `trace_application_feature` with a `channel` seed and with a `string` seed (`SignalClipboard`) both return `no-match`, although the feature exists and is traceable by hand (renderer → preload `ipcRenderer.send('SignalClipboard.copyTextTemporarily', ...)` → main `ipcMain.on(...)`). Raising the semantic limit to 1,000,000 (CLI, 45 s, 215 MB JSON) still returns 0. ### Reproduction 1. Install Signal Desktop 8.33.0 for macOS arm64 and extract `app.asar`. 2. Run `analyze-javascript-application` on the extracted directory, scoped to `package.json` and `bundles/main.js`. 3. Read the Electron view: `ipc.operations` and `browser_windows`. 4. Compare with a text count on the same file: `ipcMain.handle|on|once` and `new BrowserWindow`. ### Expected behavior Most of the 101 `ipcMain` channels (52 `handle`, 45 `on`, 8 `once`) and the 9 `BrowserWindow` constructions are recovered. The public source `app/main.main.ts` at tag v8.33.0 declares 66 channels; 65 of them are present in the bundle. If recovery fails, the result should say that Electron semantic coverage is empty or degraded, rather than reporting 0. ### Impact and scope Silent false negative on a widely used Electron app. Feature tracing and version comparison (`compare_application_versions`) depend on this graph, so they also return nothing useful. ### Relevant evidence - We could not reproduce it on synthetic files. Single-quoted and backtick `require('electron')`, plus a simulated Rolldown prologue (`c=e.o(c,1)`, `f.ipcMain.handle(...)`), are all detected correctly. The failure appears only on the real, large bundle. - Related but closed: #1656 (aliasing variables). - Also observed: a whole-ASAR run hit `provider_timeout` after 300 s on a 301 KB chunk (file 90 of 1086) and still wrote a 233 MB error JSON. The 6.5 MB preload bundle was not analysed within default limits. ### Typed outcome or recovery expected a coverage indicator for Electron semantics (for example `electron_semantics: empty | degraded`) when recovery yields nothing on a file that imports `electron`. ### REA version, runtime and platform ``` REA: rea-agents 6.8.0 (npm) Runtime: Node.js 24.22.1 Platform: macOS 27.2 (Darwin), arm64 Providers: Ghidra 12.1.4 (natives built locally with support/gradle buildNatives), OpenJDK 25.0.5, Hopper 6.6.0 demo Client: Claude Code 2.1.309–2.1.314 ```
Author
Owner

@amirg76 commented on GitHub (Nov 1, 2026):

Independent confirmation on Linux x64, plus a version bisect that points at the 6.8.0 alias-selection bound (the same mechanism as #7253, here in a Rolldown bundle).

Artifact: signal-desktop_8.33.0_amd64.deb from the official apt pool, sha256 94444da46abccca1b5832580e9bb6f659581878b7663716ae940591510d97a33 (matches the apt index). bundles/main.js in app.asar is 662,409 bytes.

Command (same input, same flags, only the npm version changes; Docker, Node 24, --network none):

rea analyze-javascript-application <extracted>/opt/Signal \
  --source-path resources/app.asar/bundles/main.js \
  --analysis-timeout-ms 1200000 --max-heap-mb 3072 --json
6.7.0 6.8.0 text count in the shipped file
browser_windows 9 0 9 × new f.BrowserWindow(
ipc.main_handlers 106 0 106 (52 handle, 45 on, 8 once, 1 handleOnce)
ipc.literal_channels 98 0
explicit_web_preferences 50 0
examination.semantic_resource_limits on main.js [] ["alias-selections"]

On 6.8.0 the evidence records for main.js carry javascript_semantic_alias_selections: 512 and the limitation "Alias selection expansion was conservatively bounded (maximum 512 additional selector states); selected paths remain unknown." On 6.7.0 that limit is never reported. Electron is bound once at the top of the bundle (let f=require(`electron`), after the Rolldown interop prologue d=e.o(d,1)), and every window and handler is a plain member read on f.

This may also explain why the synthetic files did not reproduce it: the shape is fine, but the bound only fires once the bundle is large enough. I have not traced the Rolldown path in the source, so the link to canonicalWebpackInteropBindings from #7253 is an inference, not verified.

Two details that support the coverage-indicator request in this issue. On 6.8.0 the same file reports electron_call_paths_limited: false and applicability.electron: "unknown", so nothing in the Electron view signals the loss. The only trace is the generic semantic_resource_limits entry.

Unrelated to the regression: on 6.7.0 the main window's options are reported as options_status: "dynamic" (they are built in a variable before new f.BrowserWindow(...)), so its sandbox: false is not surfaced. That looks like #3536 or #7227 rather than something new.

<!-- gh-comment-id:6556736810 --> @amirg76 commented on GitHub (Nov 1, 2026): Independent confirmation on Linux x64, plus a version bisect that points at the 6.8.0 alias-selection bound (the same mechanism as #7253, here in a Rolldown bundle). **Artifact:** `signal-desktop_8.33.0_amd64.deb` from the official apt pool, sha256 `94444da46abccca1b5832580e9bb6f659581878b7663716ae940591510d97a33` (matches the apt index). `bundles/main.js` in `app.asar` is 662,409 bytes. **Command** (same input, same flags, only the npm version changes; Docker, Node 24, `--network none`): ```sh rea analyze-javascript-application <extracted>/opt/Signal \ --source-path resources/app.asar/bundles/main.js \ --analysis-timeout-ms 1200000 --max-heap-mb 3072 --json ``` | | 6.7.0 | 6.8.0 | text count in the shipped file | |---|---|---|---| | `browser_windows` | 9 | **0** | 9 × `new f.BrowserWindow(` | | `ipc.main_handlers` | 106 | **0** | 106 (52 `handle`, 45 `on`, 8 `once`, 1 `handleOnce`) | | `ipc.literal_channels` | 98 | **0** | | | `explicit_web_preferences` | 50 | 0 | | | `examination.semantic_resource_limits` on `main.js` | `[]` | `["alias-selections"]` | | On 6.8.0 the evidence records for `main.js` carry `javascript_semantic_alias_selections: 512` and the limitation "Alias selection expansion was conservatively bounded (maximum 512 additional selector states); selected paths remain unknown." On 6.7.0 that limit is never reported. Electron is bound once at the top of the bundle (``let f=require(`electron`)``, after the Rolldown interop prologue `d=e.o(d,1)`), and every window and handler is a plain member read on `f`. This may also explain why the synthetic files did not reproduce it: the shape is fine, but the bound only fires once the bundle is large enough. I have not traced the Rolldown path in the source, so the link to `canonicalWebpackInteropBindings` from #7253 is an inference, not verified. Two details that support the coverage-indicator request in this issue. On 6.8.0 the same file reports `electron_call_paths_limited: false` and `applicability.electron: "unknown"`, so nothing in the Electron view signals the loss. The only trace is the generic `semantic_resource_limits` entry. Unrelated to the regression: on 6.7.0 the main window's options are reported as `options_status: "dynamic"` (they are built in a variable before `new f.BrowserWindow(...)`), so its `sandbox: false` is not surfaced. That looks like #3536 or #7227 rather than something new.
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#6482
No description provided.