From 35d9590f3cfb50e1863e04be72467afa231b8de5 Mon Sep 17 00:00:00 2001 From: Mike Harder Date: Thu, 14 Jun 2018 12:50:03 -0700 Subject: [PATCH] Prevent double-close race condition in ListenHandleTests.CanListenToOpenTcpSocketHandle() (#2666) --- .../ListenHandleTests.cs | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/test/Kestrel.Transport.Libuv.FunctionalTests/ListenHandleTests.cs b/test/Kestrel.Transport.Libuv.FunctionalTests/ListenHandleTests.cs index 61a24966d0..2b204cdfa0 100644 --- a/test/Kestrel.Transport.Libuv.FunctionalTests/ListenHandleTests.cs +++ b/test/Kestrel.Transport.Libuv.FunctionalTests/ListenHandleTests.cs @@ -14,26 +14,32 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests [OSSkipCondition(OperatingSystems.Windows, SkipReason = "Listening to open TCP socket and/or pipe handles is not supported on Windows.")] public class ListenHandleTests : LoggedTest { + // The Socket.Handle will be passed into libuv, which calls close() on the file descriptor when TestServer is disposed. If + // the managed Socket is also disposed or finalized, it will try to call close() again on the file descriptor, which may lead to + // race condition bugs (test hangs) if the file descriptor has been re-used for another resource. In .NET Core, objects + // assigned to static fields should never be disposed or finalized (even at process shutdown). + // https://github.com/aspnet/KestrelHttpServer/issues/2597 + private static readonly Socket _canListenToOpenTcpSocketHandleSocket = + new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + [ConditionalFact] public async Task CanListenToOpenTcpSocketHandle() { - using (var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + _canListenToOpenTcpSocketHandleSocket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); + + using (var server = new TestServer(_ => Task.CompletedTask, new TestServiceContext(LoggerFactory), + new ListenOptions((ulong)_canListenToOpenTcpSocketHandleSocket.Handle))) { - listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); - - using (var server = new TestServer(_ => Task.CompletedTask, new TestServiceContext(LoggerFactory), new ListenOptions((ulong)listenSocket.Handle))) + using (var connection = new TestConnection(((IPEndPoint)_canListenToOpenTcpSocketHandleSocket.LocalEndPoint).Port)) { - using (var connection = new TestConnection(((IPEndPoint)listenSocket.LocalEndPoint).Port)) - { - await connection.SendEmptyGet(); + await connection.SendEmptyGet(); - await connection.Receive( - "HTTP/1.1 200 OK", - $"Date: {server.Context.DateHeaderValue}", - "Content-Length: 0", - "", - ""); - } + await connection.Receive( + "HTTP/1.1 200 OK", + $"Date: {server.Context.DateHeaderValue}", + "Content-Length: 0", + "", + ""); } } }