From d68a2d45a5967f52198f552f66f658ec4a9fa675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marie=20P=C3=ADchov=C3=A1?= Date: Tue, 2 Feb 2021 16:50:34 +0100 Subject: [PATCH] Split lock to prevent deadlock between OnWindowsUpdate and Complete. Http2Connection.ChangeInitialWindowSize locks connection's SyncObject and calls Http2Stream.OnWindowUpdate which locks stream's SyncObject. Http2Stream.Complete is called only while stream's SyncObject lock is take and then it calls Http2Connection.RemoveStream that locks connection SyncObject. --- .../Net/Http/SocketsHttpHandler/Http2Stream.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs index c1ef8c1b3385b..e36b56b13da7e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs @@ -39,6 +39,7 @@ private sealed class Http2Stream : IValueTaskSource, IHttpHeadersHandler, IHttpT private int _pendingWindowUpdate; private CreditWaiter? _creditWaiter; private int _availableCredit; + private readonly object _creditSyncObject = new object(); // split from SyncObject to mitigate deadlock in OnWindowUpdate. private StreamCompletionState _requestCompletionState; private StreamCompletionState _responseCompletionState; @@ -349,11 +350,14 @@ private void Complete() _connection.RemoveStream(this); - CreditWaiter? w = _creditWaiter; - if (w != null) + lock (_creditSyncObject) { - w.Dispose(); - _creditWaiter = null; + CreditWaiter? waiter = _creditWaiter; + if (waiter != null) + { + waiter.Dispose(); + _creditWaiter = null; + } } } @@ -421,7 +425,7 @@ private void Cancel() public void OnWindowUpdate(int amount) { - lock (SyncObject) + lock (_creditSyncObject) { _availableCredit = checked(_availableCredit + amount); if (_availableCredit > 0 && _creditWaiter != null) @@ -1219,7 +1223,7 @@ private async ValueTask SendDataAsync(ReadOnlyMemory buffer, CancellationT while (buffer.Length > 0) { int sendSize = -1; - lock (SyncObject) + lock (_creditSyncObject) { if (_availableCredit > 0) {