Skip to content

Fix DisposableStore reference leak in terminal execute strategies#313369

Merged
meganrogge merged 1 commit into
mainfrom
merogge/fix-execute-strategy-store-leak
Apr 29, 2026
Merged

Fix DisposableStore reference leak in terminal execute strategies#313369
meganrogge merged 1 commit into
mainfrom
merogge/fix-execute-strategy-store-leak

Conversation

@meganrogge

Copy link
Copy Markdown
Collaborator

Fixes #313368

Problem

RichExecuteStrategy.execute() and BasicExecuteStrategy.execute() each create a per-call DisposableStore and register it on the strategy via this._register(store) (introduced in #310157). The finally { store.dispose(); } runs the children's disposers but does not remove the entry from the parent's _toDispose Set — only DisposableStore.delete(child) does. So every successful execute() leaves a stale (already-disposed) DisposableStore referenced by the strategy. A colleague observed 28 such retained stores on a single long-lived strategy.

Fix

Track in-flight stores in a dedicated _executionStores DisposableStore field and delete(store) on completion. This preserves the mid-flight disposal cleanup behavior from #310157 (if the strategy is disposed while execute() is awaiting, the in-flight store is cleaned up) while clearing the reference on the happy path.

Each execute() call registered a per-call DisposableStore via
this._register(store), but store.dispose() in the finally block does
not remove the reference from the parent _toDispose Set. Stale,
already-disposed stores accumulated across invocations on long-lived
strategies (28 observed in the wild).

Track in-flight stores in a dedicated _executionStores DisposableStore
and delete(store) on completion. Preserves the mid-flight disposal
cleanup from #310157 while clearing the reference on the happy path.

Fixes #313368
Copilot AI review requested due to automatic review settings April 29, 2026 23:20
@meganrogge meganrogge self-assigned this Apr 29, 2026
@meganrogge meganrogge added this to the 1.119.0 milestone Apr 29, 2026
@meganrogge
meganrogge enabled auto-merge (squash) April 29, 2026 23:21

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

Fixes a lifecycle leak in the terminal chat agent “run in terminal” execute strategies by ensuring per-invocation DisposableStores don’t remain referenced by long-lived strategy instances after execute() completes.

Changes:

  • Introduce a dedicated _executionStores DisposableStore on each execute strategy to track in-flight per-call stores.
  • Replace this._register(store) with _executionStores.add(store) so stores can be removed after execution.
  • Replace store.dispose() with _executionStores.delete(store) to both dispose and remove references on completion.
Show a summary per file
File Description
src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/richExecuteStrategy.ts Track per-execution disposables via _executionStores and delete them in finally to avoid retained references.
src/vs/workbench/contrib/terminalContrib/chatAgentTools/browser/executeStrategy/basicExecuteStrategy.ts Same disposal/reference cleanup pattern applied to the basic execute strategy.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 2

@meganrogge
meganrogge merged commit 9b81148 into main Apr 29, 2026
30 checks passed
@meganrogge
meganrogge deleted the merogge/fix-execute-strategy-store-leak branch April 29, 2026 23:59
@vs-code-engineering vs-code-engineering Bot locked and limited conversation to collaborators Jun 14, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Terminal execute strategies leak DisposableStore references across run_in_terminal invocations

3 participants