Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Socket.Select: increase ref count while the handle is in use #41763

Merged
merged 4 commits into from
Oct 23, 2019

Conversation

tmds
Copy link
Member

@tmds tmds commented Oct 14, 2019

@davidsh davidsh added this to the 5.0 milestone Oct 14, 2019
@davidsh davidsh requested a review from a team October 14, 2019 16:50
@wfurt
Copy link
Member

wfurt commented Oct 14, 2019

why do we need this @tmds? Should SafeHandle be sufficient to keep it alive?

{
throw new ArgumentException(SR.Format(SR.net_sockets_select, socketList[current].GetType().FullName, typeof(System.Net.Sockets.Socket).FullName), nameof(socketList));
}

fileDescriptorSet[current + 1] = ((Socket)socketList[current])._handle.DangerousGetHandle();
bool success = false;
socket.SafeHandle.DangerousAddRef(ref success);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With your other PR, accessing socket.SafeHandle is now going to mark the handle as exposed. Is that necessary? Should we instead be using _handle here and everywhere else internally where the handle is used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just added an InternalSafeHandle property to the other PR. Once it is merged, I'll rebase and use it here.

@stephentoub
Copy link
Member

why do we need this @tmds? Should SafeHandle be sufficient to keep it alive?

The problem is the implementation isn't just passing SafeHandle to P/Invokes, where the marshaling layer would implicitly addref and release around the native call. Rather, the implementation is calling DangerousGetHandle, returning the raw pointer to then be used. Any usage of that raw handle is no longer guarded by the SafeHandle; instead, the SafeHandle needs to have its ref count increased prior to any usage of the raw handle and its ref count then decremented after. Otherwise, Dispose'ing of the SafeHandle could cause the handle to be closed and even recycled while it's still in use.

@wfurt
Copy link
Member

wfurt commented Oct 14, 2019

why do we need this @tmds? Should SafeHandle be sufficient to keep it alive?

The problem is the implementation isn't just passing SafeHandle to P/Invokes, where the marshaling layer would implicitly addref and release around the native call. Rather, the implementation is calling DangerousGetHandle, returning the raw pointer to then be used. Any usage of that raw handle is no longer guarded by the SafeHandle; instead, the SafeHandle needs to have its ref count increased prior to any usage of the raw handle and its ref count then decremented after. Otherwise, Dispose'ing of the SafeHandle could cause the handle to be closed and even recycled while it's still in use.

I was under impression that was fixed in 3.0. If not, shoud we pass SafeHandle to the call?
I did not see any linked issues so I'm trying understand where this come form.

@stephentoub
Copy link
Member

shoud we pass SafeHandle to the call?

We need to be able to pass a variable number of handles / file descriptors in an array; we can't do that with SafeHandle.

I was under impression that was fixed in 3.0.

What specifically?

@tmds
Copy link
Member Author

tmds commented Oct 15, 2019

I was under impression that was fixed in 3.0.

For the operations that take a single handle, the raw values were replaced by SafeHandle marshalling as part of #38804. Socket.Select wasn't changed yet.

@stephentoub
Copy link
Member

stephentoub commented Oct 21, 2019

The failures here (at least some of them) appear to be related hangs:

[Long Running Test] 'System.Net.Sockets.Tests.AcceptSync.AcceptGetsCanceledByDispose', Elapsed: 00:14:36
[Long Running Test] 'System.Net.Sockets.Tests.ConnectSync.ConnectGetsCanceledByDispose', Elapsed: 00:14:34
[Long Running Test] 'System.Net.Sockets.Tests.SocketOptionNameTest.MulticastInterface_Set_Loopback_Succeeds', Elapsed: 00:14:36
[Long Running Test] 'System.Net.Sockets.Tests.SendReceiveSpanSync.TcpPeerReceivesFinOnShutdownWithPendingData', Elapsed: 00:14:36
[Long Running Test] 'System.Net.Sockets.Tests.SendReceiveEap.SendAsync_ConcurrentDispose_SucceedsOrThrowsAppropriateException', Elapsed: 00:14:32
[Long Running Test] 'System.Net.Sockets.Tests.ConnectApm.ConnectGetsCanceledByDispose', Elapsed: 00:14:34
[Long Running Test] 'System.Net.Sockets.Tests.DualModeBeginConnectToIPAddress.BeginConnectV4IPAddressToV6Host_Fails', Elapsed: 00:14:24
[Long Running Test] 'System.Net.Sockets.Tests.AcceptSyncForceNonBlocking.AcceptGetsCanceledByDispose', Elapsed: 00:14:32
[Long Running Test] 'System.Net.Sockets.Tests.SendReceiveTask.SendAsync_ConcurrentDispose_SucceedsOrThrowsAppropriateException', Elapsed: 00:14:32
[Long Running Test] 'System.Net.Sockets.Tests.DualModeBeginConnect.DualModeBeginConnect_DnsEndPointToHost_Helper', Elapsed: 00:14:32
[Long Running Test] 'System.Net.Sockets.Tests.ConnectSyncForceNonBlocking.ConnectGetsCanceledByDispose', Elapsed: 00:14:24
[Long Running Test] 'System.Net.Sockets.Tests.DisposedSocket.NonDisposedSocket_SafeHandlesCollected', Elapsed: 00:14:24
[Long Running Test] 'System.Net.Sockets.Tests.AcceptTask.AcceptAsync_MultipleAcceptsThenDispose_AcceptsThrowAfterDispose', Elapsed: 00:14:24
[Long Running Test] 'System.Net.Sockets.Tests.ConnectEap.ConnectGetsCanceledByDispose', Elapsed: 00:14:24
[Long Running Test] 'System.Net.Sockets.Tests.DualModeBeginConnectToIPEndPoint.BeginConnectV6IPEndPointToV6Host_Success', Elapsed: 00:14:18
[Long Running Test] 'System.Net.Sockets.Tests.AcceptEap.AcceptGetsCanceledByDispose', Elapsed: 00:14:24
[Long Running Test] 'System.Net.Sockets.Tests.SelectAndPollTests.SelectRead_Single_Timeout', Elapsed: 00:14:10
[Long Running Test] 'System.Net.Sockets.Tests.SendReceiveSpanSyncForceNonBlocking.Receive0ByteReturns_WhenPeerDisconnects', Elapsed: 00:14:18
[Long Running Test] 'System.Net.Sockets.Tests.ConnectTask.Connect_OnConnectedSocket_Fails', Elapsed: 00:14:18
[Long Running Test] 'System.Net.Sockets.Tests.ArgumentValidation.Socket_Connect_DnsEndPointWithIPAddressString_Supported', Elapsed: 00:14:18
[Long Running Test] 'System.Net.Sockets.Tests.SelectTest.Select_ReadError_NoneReady', Elapsed: 00:14:18

@stephentoub
Copy link
Member

/azp run corefx-ci

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@tmds
Copy link
Member Author

tmds commented Oct 22, 2019

On Windows, there were missing unrefs. This is fixed and ci is now passing.
@stephentoub can you give it another run, to check if everything stays green?

@stephentoub
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 4 pipeline(s).

Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

@stephentoub stephentoub merged commit 6c62c7f into dotnet:master Oct 23, 2019
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
…corefx#41763)

* Socket.Select: increase ref count while the handle is in use

* PR feedback

* Use Socket.InternalSafeHandle for ref/release.

* Socket.Windows: SelectFileDescriptor: add missing unrefs


Commit migrated from dotnet/corefx@6c62c7f
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants