microsoft / microsoft/vs-streamjsonrpc

Resource leak in IAsyncEnumerable client-side disposal: server not notified on normal enumeration completion

Open
#1,386 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
937
Forks
178
Avg merge
3d 1h
Merged PRs (30d)
28

Description

I have a RPC interface defined like:

IAsyncEnumerable<Response> GetStates(Request request, CancellationToken token = default);
and there is a property with type of IAsyncEnumerable<Operation> in request parameter.

Summary
The AsyncEnumeratorProxy in MessageFormatterEnumerableTracker.cs fails to notify the server to dispose of the enumerator when enumeration completes normally (all values consumed). This causes a resource leak on the server side where enumerators remain tracked in the generatorsByToken dictionary indefinitely.

Root Cause
In AsyncEnumeratorProxy.DisposeAsync() (line 452), the disposal notification is only sent when generatorReportsFinished is false:
if (!this.generatorReportsFinished)
{
await this.owner.jsonRpc.NotifyAsync(DisposeMethodName, this.nextOrDisposeArguments).ConfigureAwait(false);
}
However, when enumeration completes normally:
The server sets results.Finished = true (line 327)
The client receives this and sets this.generatorReportsFinished = true (line 497)
When the await foreach loop completes and DisposeAsync() is called, the condition at line 452 evaluates to false
No disposal notification is sent to the server

Impact
Memory leak: Server-side enumerators remain in generatorsByToken dictionary until connection dies
Resource leak: Any resources held by the server-side GeneratingEnumeratorTracker are not properly disposed
Accumulation: Each completed enumeration leaves behind leaked resources in long-running connections

Expected Behavior
The client should always notify the server when disposing an enumerator, regardless of whether generatorReportsFinished is true. The server needs this notification to:
Remove the enumerator from generatorsByToken dictionary
Call DisposeAsync() on the GeneratingEnumeratorTracker instance
Release any associated resources

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in MessageFormatterEnumerableTracker.cs at AsyncEnumeratorProxy.DisposeAsync() and trace how generatorReportsFinished is set when enumeration completes. Confirm the disposal notification is sent after normal completion, so the server removes the enumerator from generatorsByToken and disposes its GeneratingEnumeratorTracker resources.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
backend-api-design, distributed-systems
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.