Skip to content

Fix multi-diff and native host event leaks - #328317

Merged
hediet merged 3 commits into
microsoft:mainfrom
roblourens:roblou/agents/do-you-see-any-legitimate-memory-leaks-in
Jul 31, 2026
Merged

Fix multi-diff and native host event leaks#328317
hediet merged 3 commits into
microsoft:mainfrom
roblourens:roblou/agents/do-you-see-any-legitimate-memory-leaks-in

Conversation

@roblourens

@roblourens roblourens commented Jul 30, 2026

Copy link
Copy Markdown
Member

Problem

This fixes two independent leaks surfaced by disposable and event-buffer diagnostics.

Failed multi-diff model resolution

Opening the Agents window Changes multi-diff can attempt to resolve entries that cannot be opened as text, such as a directory or binary file. If either createModelReference call rejected, the surrounding Promise.all returned immediately without disposing the per-item DisposableStore. A reference acquired by the other call could also be lost without disposal, including when that call completed after its sibling had already rejected.

This produced [LEAKED DISPOSABLE] warnings rooted in MultiDiffEditorInput._createModel and could retain text model references after failed multi-diff item resolution.

Unconsumed native host blur buffer

ProxyChannel.fromService eagerly subscribes to and buffers service events so startup events can be replayed when an IPC client attaches. onDidBlurMainWindow has no IPC consumer, so every main-window blur was retained indefinitely and the eager proxy subscription was unnecessary. In dev builds this produced an [Event.buffer][onDidBlurMainWindow] potential LEAK detected warning after buffered events remained unconsumed.

This is long-standing rather than a recent regression:

  • 42f5594892 (2023-11-02) split focus/blur into main-only and main-or-auxiliary events. Renderer consumers moved to the combined event, leaving the main-only blur buffer without an IPC listener.
  • a837f16fbe (2026-02-28) added Event.buffer leak diagnostics, making the existing unbounded buffer visible.

The main-only focus event remains buffered intentionally because Settings Sync consumes it through the shared-process native host channel.

Fix

  • wait for both model-reference acquisitions with Promise.allSettled
  • dispose the multi-diff item store when either acquisition fails or when its cached item is removed while resolution is pending
  • preserve handling for synchronous model-reference failures
  • add an opt-in unbufferedEvents proxy-channel option that subscribes only when an IPC client listens
  • make onDidBlurMainWindow lazy/unbuffered while preserving the event API for future consumers
  • cover lazy subscription, lack of replay, and listener cleanup with an IPC unit test

CC @hediet, who authored the original multi-diff model-resolution path.

Validation

  • npm run gulp compile
  • npm run typecheck-client
  • ./scripts/test.sh --run src/vs/base/parts/ipc/test/common/ipc.test.ts (23 passing)
  • npm run precommit

(Written by Copilot)

Wait for both model reference acquisitions and dispose any successful references when the other side fails or the cached item is removed.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 30, 2026 23:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Makes multi-diff model reference acquisition more failure-safe by ensuring partial successes are disposed when the other acquisition fails, and by handling disposal during in-flight acquisition.

Changes:

  • Switched from Promise.all to Promise.allSettled for original/modified model reference acquisition.
  • Disposes successfully acquired references when the other acquisition fails.
  • Disposes acquired references if the parent store was disposed while acquisitions were in progress.
Show a summary per file
File Description
src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditorInput.ts Ensures model references are cleaned up correctly across partial failures and disposal during acquisition

Review details

  • Files reviewed: 1/1 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditorInput.ts Outdated
Preserve handling for synchronous model-reference failures and make rejection selection easier to follow.\n\n(Written by Copilot)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@hediet
hediet marked this pull request as ready for review July 31, 2026 09:14
@hediet
hediet enabled auto-merge (rebase) July 31, 2026 09:17
@hediet
hediet merged commit 92abb76 into microsoft:main Jul 31, 2026
29 checks passed
@vs-code-engineering vs-code-engineering Bot added this to the 1.132.0 milestone Jul 31, 2026
@roblourens roblourens changed the title multiDiffEditor: Dispose partial model references on failure Fix multi-diff and native host event leaks Aug 1, 2026
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.

3 participants