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

Socket.Select throws ObjectDisposedException when one of the sockets is disposed #34886

Closed
drieseng opened this issue Apr 13, 2020 · 9 comments · Fixed by dotnet/dotnet-api-docs#4720
Assignees
Labels
area-System.Net.Sockets breaking-change Issue or PR that represents a breaking API or functional change over a prerelease. documentation Documentation bug or enhancement, does not impact product or test code tenet-compatibility Incompatibility with previous versions or .NET Framework
Milestone

Comments

@drieseng
Copy link
Contributor

In (desktop) .NET Framework, Socket.Select(....) throws a SocketException when one of the sockets that you specify is disposed:

System.Net.Sockets.SocketException (10038): An operation was attempted on something that is not a socket.

In .NET Core 2.1 and 3.1, this is also the exception that is thrown on Windows. On Linux, no exception is thrown.

Now in .NET 5.0 Preview 2, an ObjectDisposedException is thrown on both Windows and Linux:

System.ObjectDisposedException: Safe handle has been closed.
Object name: 'SafeHandle'.
at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)
at System.Net.Sockets.SocketPal.AddToPollArray(PollEvent* arr, Int32 arrLength, IList socketList, Int32& arrOffset, PollEvents events, Int32& refsAdded)
at System.Net.Sockets.SocketPal.SelectViaPoll(IList checkRead, Int32 checkReadInitialCount, IList checkWrite, Int32 checkWriteInitialCount, IList checkError, Int32 checkErrorInitialCount, PollEvent* events, Int32 eventsLength, Int32 microseconds)
at System.Net.Sockets.SocketPal.Select(IList checkRead, IList checkWrite, IList checkError, Int32 microseconds)
at System.Net.Sockets.Socket.Select(IList checkRead, IList checkWrite, IList checkError, Int32 microSeconds)

To reproduce, compile and run the following code fragment:

using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

class SelectDisposed
{
    private static void Main()
    {
        var endPoint = new IPEndPoint(IPAddress.Loopback, 8080);
        var client = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        client.Dispose();

        Socket.Select(new List<object> { client }, null, null, -1);
    }
}
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Net.Sockets untriaged New issue has not been triaged by the area owner labels Apr 13, 2020
@ghost
Copy link

ghost commented Apr 13, 2020

Tagging @dotnet/ncl as an area owner. If you would like to be tagged for a label, please notify danmosemsft.

@tmds
Copy link
Member

tmds commented Apr 13, 2020

This is caused by dotnet/corefx#41763.

With the old behavior, no reference counting was performed. The SocketException refers to using a handle which is no longer a socket.
In a worse scenario, the handle could have been reused for a different Socket causing the Select to be performed against the wrong socket.

With the change, Select will require the handle to be valid. If the handle is not valid ODE is thrown.

@karelz
Copy link
Member

karelz commented Apr 13, 2020

So it is technical breaking change in 5.0.
We should either document it as such, or wrap the ObjectDisposedException in SocketException.

@drieseng how did you discover the difference? Did you run into it in your app?

@karelz karelz removed the untriaged New issue has not been triaged by the area owner label Apr 13, 2020
@karelz karelz added this to the 5.0 milestone Apr 13, 2020
@karelz karelz added bug tenet-compatibility Incompatibility with previous versions or .NET Framework labels Apr 13, 2020
@stephentoub
Copy link
Member

So it is technical breaking change in 5.0. We should either document it as such

It's fine to document it. It's a bug that should have been fixed years ago when things were moved to be SafeHandle-based. It's a handle-recycling issue.

@karelz karelz added documentation Documentation bug or enhancement, does not impact product or test code breaking-change Issue or PR that represents a breaking API or functional change over a prerelease. and removed bug labels Apr 13, 2020
@karelz
Copy link
Member

karelz commented Apr 13, 2020

OK, marking as such. cc @antonfirsov

@drieseng
Copy link
Contributor Author

drieseng commented Apr 15, 2020

I'm really impressed by the speed at which this decision was taken and verified across all implementations (.NET, Mono, ...). Because this is how such a thing is done, right ?

Note that I'm ok with this decision, but I would expect there to be more discussion on such changes (even if you can consider it an implementation detail). In the desktop framework, there was a very high level of compatibility and a slower pace of innovation. I definitely welcome the high pace of innovation that we have right now, but I get the impression that compatibility is sometimes abandoned all too fast. This specific issue is perhaps not the best example of this, but it does show easy "breaking" changes are introduced.

@danmoseley
Copy link
Member

It is certainly nice that the test is running on Mono automatically. It shows the value of all being in one repo.

@drieseng
Copy link
Contributor Author

That's indeed true.

@karelz
Copy link
Member

karelz commented Sep 1, 2020

Fixed by PR dotnet/dotnet-api-docs#4720

@karelz karelz closed this as completed Sep 1, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net.Sockets breaking-change Issue or PR that represents a breaking API or functional change over a prerelease. documentation Documentation bug or enhancement, does not impact product or test code tenet-compatibility Incompatibility with previous versions or .NET Framework
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants