Fix assert in poll_event_wait() on WSAENOTSOCK on Windows
authorNiklas Therning <niklas@therning.org>
Mon, 21 Nov 2016 09:17:40 +0000 (10:17 +0100)
committerNiklas Therning <niklas@therning.org>
Mon, 21 Nov 2016 14:00:41 +0000 (15:00 +0100)
On Windows poll_event_wait() in threadpool-ms-io-poll.c checks
WSAGetLastError() when mono_poll() fails. However, mono_poll() sets errno
after converting the WSAXXX error code (e.g. WSAEFAULT->EFAULT). Occasionally
(maybe 1 in 100) the System test suite fails due to mono_poll() returning an
error and poll_event_wait() not handling the error code correctly on Windows.

This patch changes poll_event_wait() to use the same code path which checks
errno on all platforms including Windows. It also fixes a few other places
which used to check WSAGetLastError() rather than errno after a call to
mono_poll(). Also, the Socket.Poll_internal() and Socket.Select_internal()
icalls had to be patched to convert back the errno value to a corresponding
WSAXXX error code by adding WSABASEERR on Windows.

mono/metadata/socket-io.c
mono/metadata/threadpool-ms-io-poll.c

index b5866b73a22bb730dc3109f85cf6c7576e1f7662..2e04a8e3dabd8eed37298704bcdcc3af2cee242a 100644 (file)
@@ -1242,7 +1242,7 @@ ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
 
        if (ret == -1) {
 #ifdef HOST_WIN32
-               *werror = WSAGetLastError ();
+               *werror = errno > 0 && errno < WSABASEERR ? errno + WSABASEERR : errno;
 #else
                *werror = errno_to_WSA (errno, __func__);
 #endif
@@ -1868,7 +1868,7 @@ ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArray **sockets, gint32
        
        if (ret == -1) {
 #ifdef HOST_WIN32
-               *werror = WSAGetLastError ();
+               *werror = errno > 0 && errno < WSABASEERR ? errno + WSABASEERR : errno;
 #else
                *werror = errno_to_WSA (errno, __func__);
 #endif
index 68e6611fba2619ee83cb65ea78cf16c249549c37..3d32130d3b530cc14ad38ce04cffaf5258ac28cf 100644 (file)
@@ -117,11 +117,7 @@ poll_mark_bad_fds (mono_pollfd *poll_fds, gint poll_fds_size)
                        ready++;
                        break;
                case -1:
-#if !defined(HOST_WIN32)
                        if (errno == EBADF)
-#else
-                       if (WSAGetLastError () == WSAEBADF)
-#endif
                        {
                                poll_fds [i].revents |= MONO_POLLNVAL;
                                ready++;
@@ -163,37 +159,21 @@ poll_event_wait (void (*callback) (gint fd, gint events, gpointer user_data), gp
                 *  ENOMEM: we're doomed anyway
                 *
                 */
-#if !defined(HOST_WIN32)
                switch (errno)
-#else
-               switch (WSAGetLastError ())
-#endif
                {
-#if !defined(HOST_WIN32)
                case EINTR:
-#else
-               case WSAEINTR:
-#endif
                {
                        mono_thread_internal_check_for_interruption_critical (mono_thread_internal_current ());
                        ready = 0;
                        break;
                }
-#if !defined(HOST_WIN32)
                case EBADF:
-#else
-               case WSAEBADF:
-#endif
                {
                        ready = poll_mark_bad_fds (poll_fds, poll_fds_size);
                        break;
                }
                default:
-#if !defined(HOST_WIN32)
                        g_error ("poll_event_wait: mono_poll () failed, error (%d) %s", errno, g_strerror (errno));
-#else
-                       g_error ("poll_event_wait: mono_poll () failed, error (%d)\n", WSAGetLastError ());
-#endif
                        break;
                }
        }