From b248f408c7b7475fea0732848728f8e549fa10c9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 24 Jul 2020 10:59:10 -0600 Subject: [PATCH] Avoid crashing .NET Core processes while canceling async I/O Workaround for https://github.com/dotnet/runtime/issues/39902 --- src/Nerdbank.Streams/PipeExtensions.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Nerdbank.Streams/PipeExtensions.cs b/src/Nerdbank.Streams/PipeExtensions.cs index cb2c1eb1..66d7a45c 100644 --- a/src/Nerdbank.Streams/PipeExtensions.cs +++ b/src/Nerdbank.Streams/PipeExtensions.cs @@ -469,7 +469,21 @@ private static PipeReader UsePipeReader(this Stream stream, int sizeHint = 0, Pi // we can return a decorated PipeReader that calls us from its Complete method directly. var combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); #pragma warning disable CS0618 // Type or member is obsolete - pipe.Writer.OnReaderCompleted((ex, state) => ((CancellationTokenSource)state).Cancel(), combinedTokenSource); + pipe.Writer.OnReaderCompleted( + (ex, state) => + { + try + { + ((CancellationTokenSource)state).Cancel(); + } + catch (AggregateException cancelException) + { + // .NET Core may throw this when canceling async I/O (https://github.com/dotnet/runtime/issues/39902). + // Just swallow it. We've canceled what we intended to. + cancelException.Handle(x => x is ObjectDisposedException); + } + }, + combinedTokenSource); // When this argument is provided, it provides a means to ensure we don't hang while reading from an I/O pipe // that doesn't respect the CancellationToken. Disposing a Stream while reading is a means to terminate the ReadAsync operation.