NullReferenceException, bug in C# socket BeginConnect?
See the question and my original answer on StackOverflowI'm pretty confident this uncatchable error is caused by a bug in the Socket code and you should report it to connect.
Here is an extract from the Socket.cs code at .NET reference source: http://referencesource.microsoft.com/#System/net/System/Net/Sockets/Socket.cs,938ed6a18154d0fc
private void ConnectCallback()
{
LazyAsyncResult asyncResult = (LazyAsyncResult) m_AcceptQueueOrConnectResult;
// If we came here due to a ---- between BeginConnect and Dispose
if (asyncResult.InternalPeekCompleted)
{
// etc.
return;
}
}
This callback is called by another static method:
private static void RegisteredWaitCallback(object state, bool timedOut)
{
Socket me = (Socket)state;
// Interlocked to avoid a race condition with DoBeginConnect
if (Interlocked.Exchange(ref me.m_RegisteredWait, null) != null)
{
switch (me.m_BlockEventBits)
{
case AsyncEventBits.FdConnect:
me.ConnectCallback();
break;
case AsyncEventBits.FdAccept:
me.AcceptCallback(null);
break;
}
}
}
This static method is never unregistered, it's always called, but it relies on a m_RegisteredWait
event to determine if it must pass on to the socket member method.
The problem is I suppose this event is sometimes not null while the m_AcceptQueueOrConnectResult
can be null, which causes the problem, in an uncatchable thread.
That being said, the root cause of the problem is the fact that your code exhibits problems in the first place as others have noted. To avoid this horrible uncatchable error, just make sure you call Close
or Dispose
on the socket when error happens and this will internally clear the m_RegisteredWait
member. For example, the BeginConnect documentation says this:
To cancel a pending call to the BeginConnect method, close the Socket. When the Close method is called while an asynchronous operation is in progress, the callback provided to the BeginConnect method is called. A subsequent call to the EndConnect method will throw an ObjectDisposedException to indicate that the operation has been cancelled.
In your example, just add the following line to your callback code:
private static void ConnectCallback(IAsyncResult ar)
{
try
{
...
}
catch (Exception e)
{
if (_socket != null) _socket.Dispose();
}
}
Now, you'll still have errors but they will be normal errors.