microsoft / microsoft/vs-streamjsonrpc
Resource leak in IAsyncEnumerable client-side disposal: server not notified on normal enumeration completion
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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