Skip to content

Closing the AsyncWaitHandle from the result of socket.BeginConnect crashes the application in .NET 6.0 #64400

Description

@MaxG117

Description

The simple code below works on all versions of .NET before 6.0, but crashes with "Unhandled exception. System.ObjectDisposedException: Safe handle has been closed." on net6.0:

using System;
using System.Net;
using System.Net.Sockets;

namespace Net60SafeHandleBug
{
    class Program
    {
        static void Main(string[] args)
        {
            int port = 1234;
            IPAddress.TryParse("127.0.0.1", out IPAddress ipAddress);
            Socket socket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            IAsyncResult asyncResult = socket.BeginConnect(ipAddress, port, null, null);
            // do something, then suddenly quit...
            socket.Close();
            asyncResult.AsyncWaitHandle.Close(); // <-- ruh roh

            Console.WriteLine("Press any key to quit...");
            Console.ReadKey();
        }
    }
}

Reproduction Steps

Build the above code as a console app. It will crash when targeting net6.0, but work fine with any older version of .NET.

Expected behavior

The application should succeed. The documentation for IAsyncResult.AsyncWaitHandle does not mention that one must wait for the handle to be signaled or call the APM End* method before closing, but it does say that the handle should be closed when the application is done using it.

Actual behavior

The application crashes with the following:

System.ObjectDisposedException
  HResult=0x80131622
  Message=Safe handle has been closed.
Object name: 'SafeHandle'.
  Source=System.Private.CoreLib
  StackTrace:
   at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)
   at Interop.Kernel32.SetEvent(SafeWaitHandle handle)
   at System.Threading.EventWaitHandle.Set()
   at System.Threading.ManualResetEventSlim.Set(Boolean duringCancellation)
   at System.Threading.Tasks.Task.FinishStageTwo()
   at System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute)
   at System.Threading.Tasks.Task.TrySetException(Object exceptionObject)
   at System.Threading.Tasks.ValueTask.ValueTaskSourceAsTask.<>c.<.cctor>b__4_0(Object state)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.InvokeContinuation(Action`1 continuation, Object state, Boolean forceAsync, Boolean requiresExecutionContextFlow)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.OnCompleted(SocketAsyncEventArgs _)
   at System.Net.Sockets.SocketAsyncEventArgs.OnCompletedInternal()
   at System.Net.Sockets.SocketAsyncEventArgs.HandleCompletionPortCallbackError(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
   at System.Net.Sockets.SocketAsyncEventArgs.<>c.<.cctor>b__179_0(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
   at System.Threading.ThreadPoolBoundHandleOverlapped.CompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
   at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pNativeOverlapped)

Regression?

This is a regression in .NET 6.0, because it works in all the prior versions.

Known Workarounds

No response

Configuration

Tested on net461, netcoreapp2.0, net5.0, and net6.0 running on Windows 10 (x64). Did not test on other platforms.

Other information

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions