What causes a NullReferenceException in .NET Threading / Accepting TCP Connections?

In my own web server software, I get entries in the event viewer on the server that contain the following stack trace:

Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.ArgumentNullException Stack: at System.Net.FixedSizeReader.ReadCallback(System.IAsyncResult) at System.Net.LazyAsyncResult.Complete(IntPtr) at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) at System.Net.ContextAwareResult.Complete(IntPtr) at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*) 

Needless to say, this leads to a process crash, which means that the server is down.

Since none of the stacktrace mentions my own code, I am very puzzled. Is this a bug in .NET? If so, are there any known workarounds? Or is there a known reason for this particular exception?

The name CompletionPortCallback given in stacktrace makes me think that this happens when the server tries to accept an incoming TCP connection, so I'm going to include the appropriate code for this below. Of course, I'm glad to include another code if you think the problem lies elsewhere.

The BeginAccept call is as follows:

 _listeningSocket.BeginAccept(acceptSocket, null); 

Here _listeningSocket is of type System.Net.Sockets.Socket .

Below is the acceptSocket method. I'm going to suggest that the comments explain the code well enough; if not, I am happy to clarify in the comment. Since this code works in RELEASE mode on a real server, #if DEBUG will of course be false.

 private void acceptSocket(IAsyncResult result) { #if DEBUG // Workaround for bug in .NET 4.0 and 4.5: // https://connect.microsoft.com/VisualStudio/feedback/details/535917 new Thread(() => #endif { // Ensure that this callback is really due to a new connection (might be due to listening socket closure) if (!IsListening) return; // Get the socket Socket socket = null; try { socket = _listeningSocket.EndAccept(result); } catch (SocketException) { } // can happen if the remote party has closed the socket while it was waiting for us to accept catch (ObjectDisposedException) { } catch (NullReferenceException) { if (_listeningSocket != null) throw; } // can happen if StopListening is called at precisely the "wrong" time // Schedule the next socket accept if (_listeningSocket != null) try { _listeningSocket.BeginAccept(acceptSocket, null); } catch (NullReferenceException) { if (_listeningSocket != null) throw; } // can happen if StopListening is called at precisely the "wrong" time // Handle this connection if (socket != null) HandleConnection(socket); } #if DEBUG ).Start(); #endif } 
+6
source share
3 answers

The answer is as simple as disappointment.

It turns out that ArgumentNullException indeed thrown by my own code, which was executed in the asynchronous callback and should have been in the stack trace. I trusted the stack trace too much; the fact that this did not appear in the stack trace led me to the wrong track for a long time.

As C # developers know, the throw; statement throw; (do not throw e; ) must support unchanged tracing of the exception stack. System.Net.FixedSizeReader.ReadCallback captures and throws an exception using such a throw; statement throw; but the stack trace shown in the event viewer is truncated. I can only guess that this is an error in the CLR or Event Viewer or some kind of interaction between them, as a result of which only part of the stack trace from the throw; statement is displayed throw; .

When I ran the software on the console instead of the service I was supposed to think about, most likely, a full trace of the exception stack showed on the console, which indicates that the true reason for the exception was my own code.

+4
source

Based on https://connect.microsoft.com/VisualStudio/feedback/details/535917 and my own experience, this is most likely a knockout exception from another earlier problem.

Try adding a global exception handler and write and clear all exceptions on disk, and then check the log file after a crash to find the real cause.

0
source

I think this exception is thrown because you are passing a null reference as the second parameter.

From the MSDN documentation Socket.BeginAccept ( http://msdn.microsoft.com/de-de/library/5bb431f9.aspx ):

You must create a callback method that implements the AsyncCallback delegate and passes its name to the BeginAccept method. To do this, at a minimum, you must pass the listening Socket object to BeginAccept via the status parameter. If your callback requires additional information, you can create a small class to store Socket and other required information. Pass an instance of this class to the BeginAccept method via the status parameter.

-1
source

Source: https://habr.com/ru/post/953220/


All Articles