Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MultiplexingStream.Dispose races with itself and throws NRE #129

Closed
AArnott opened this issue Oct 3, 2019 · 2 comments
Closed

MultiplexingStream.Dispose races with itself and throws NRE #129

AArnott opened this issue Oct 3, 2019 · 2 comments
Assignees
Milestone

Comments

@AArnott
Copy link
Collaborator

AArnott commented Oct 3, 2019

When calling MultiplexingStream.Dispose I witnessed an NRE with this callstack:

 	mscorlib.dll!System.IO.BufferedStream.Dispose(bool disposing) Line 275	C#
 	mscorlib.dll!System.IO.Stream.Close() Line 249	C#
 	mscorlib.dll!System.IO.Stream.Dispose() Line 261	C#
 	Microsoft.VisualStudio.LiveShare.Rpc.Json.dll!Microsoft.Cascade.Rpc.Json.SafeWriteBufferedStream.DisposeWritable() Line 46	C#
 	Microsoft.VisualStudio.LiveShare.Rpc.Json.dll!Microsoft.Cascade.Rpc.Json.WrappedStream.Dispose(bool disposing) Line 104	C#
 	mscorlib.dll!System.IO.Stream.Close() Line 249	C#
 	mscorlib.dll!System.IO.Stream.Dispose() Line 261	C#
 	Nerdbank.Streams.dll!Nerdbank.Streams.MultiplexingStream.Dispose(bool disposing)	Unknown
 	Nerdbank.Streams.dll!Nerdbank.Streams.MultiplexingStream.Dispose()	Unknown
>	Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.Services.LiveShareServiceBrokerIntegration.ServiceBrokerHost.CreateServiceAsync.AnonymousMethod__1() Line 245	C#

The NRE would be caused by calling BufferedStream.Dispose concurrently on two threads. Could MultiplexingStream be responsible for calling Dispose on itself from another thread while we are calling Dispose on it? If so, we should ensure it's safe to call Dispose on it explicitly.

@AArnott AArnott added this to the v2.4 milestone Oct 3, 2019
@AArnott
Copy link
Collaborator Author

AArnott commented Oct 3, 2019

Yes: MultiplexingStream calls dispose on itself:

https://github.com/AArnott/Nerdbank.Streams/blob/f751349ae7f5e9b68258d307fe71def015f39bc2/src/Nerdbank.Streams/MultiplexingStream.cs#L726

What's more, it could protect the underlying stream from being disposed on two threads by just rearranging the order of these two lines:

https://github.com/AArnott/Nerdbank.Streams/blob/f751349ae7f5e9b68258d307fe71def015f39bc2/src/Nerdbank.Streams/MultiplexingStream.cs#L541-L542

@AArnott AArnott self-assigned this Oct 3, 2019
@AArnott
Copy link
Collaborator Author

AArnott commented Oct 3, 2019

In fact I even caught the self-closing callstack as the NRE throwing stack in another occurrence:

>	mscorlib.dll!System.IO.BufferedStream.Dispose(bool disposing) Line 275	C#
 	mscorlib.dll!System.IO.Stream.Close() Line 249	C#
 	mscorlib.dll!System.IO.Stream.Dispose() Line 261	C#
 	Microsoft.VisualStudio.LiveShare.Rpc.Json.dll!Microsoft.Cascade.Rpc.Json.SafeWriteBufferedStream.DisposeWritable() Line 46	C#
 	Microsoft.VisualStudio.LiveShare.Rpc.Json.dll!Microsoft.Cascade.Rpc.Json.WrappedStream.Dispose(bool disposing) Line 104	C#
 	mscorlib.dll!System.IO.Stream.Close() Line 249	C#
 	mscorlib.dll!System.IO.Stream.Dispose() Line 261	C#
 	Nerdbank.Streams.dll!Nerdbank.Streams.MultiplexingStream.Dispose(bool disposing) Line 542	C#
 	Nerdbank.Streams.dll!Nerdbank.Streams.MultiplexingStream.ReadStreamAsync() Line 726	C#

@AArnott AArnott changed the title Does MultiplexingStream.Dispose race with itself? MultiplexingStream.Dispose races with itself and throws NRE Oct 3, 2019
@AArnott AArnott closed this as completed Oct 3, 2019
AArnott added a commit that referenced this issue Jun 7, 2022
Collect test diagnostic logs
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

No branches or pull requests

1 participant