[io-layer] Fix two race conditions, one on FD handle creation and one on interrupt...
authorRodrigo Kumpera <kumpera@gmail.com>
Wed, 28 Jun 2017 22:48:28 +0000 (15:48 -0700)
committerRodrigo Kumpera <kumpera@gmail.com>
Wed, 28 Jun 2017 22:48:28 +0000 (15:48 -0700)
mono_w32handle_new_fd: We must hold scan_mutex while initializing an unallocated handle otherwise
mono_w32handle_foreach might think it's a valid handle.

mono_w32handle_timedwait_signal_handle: We must increment the refcount before installing the interrupt handle
as the other end can be called right after we finish installing and would trigger a failure.

mono/metadata/w32handle.c

index f6862a9a7dba737452b39cb840286b84d52883c1..9ecec767ba0e66b796f442982b5656f7c4784baf 100644 (file)
@@ -451,19 +451,17 @@ gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd,
        fd_index = SLOT_INDEX (fd);
        fd_offset = SLOT_OFFSET (fd);
 
+       mono_os_mutex_lock (&scan_mutex);
        /* Initialize the array entries on demand */
        if (!private_handles [fd_index]) {
-               mono_os_mutex_lock (&scan_mutex);
-
                if (!private_handles [fd_index])
                        private_handles [fd_index] = g_new0 (MonoW32HandleBase, HANDLE_PER_SLOT);
-
-               mono_os_mutex_unlock (&scan_mutex);
        }
 
        handle_data = &private_handles [fd_index][fd_offset];
 
        if (handle_data->type != MONO_W32HANDLE_UNUSED) {
+               mono_os_mutex_unlock (&scan_mutex);
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_W32HANDLE, "%s: failed to create %s handle, fd is already in use", __func__, mono_w32handle_ops_typename (type));
                /* FIXME: clean up this handle?  We can't do anything
                 * with the fd, cos thats the new one
@@ -475,6 +473,8 @@ gpointer mono_w32handle_new_fd (MonoW32HandleType type, int fd,
 
        mono_w32handle_init_handle (handle_data, type, handle_specific);
 
+       mono_os_mutex_unlock (&scan_mutex);
+
        return(GUINT_TO_POINTER(fd));
 }
 
@@ -1080,10 +1080,12 @@ mono_w32handle_timedwait_signal_handle (gpointer handle, guint32 timeout, gboole
                *alerted = FALSE;
 
        if (alerted) {
+               mono_w32handle_ref (handle);
                mono_thread_info_install_interrupt (signal_handle_and_unref, handle, alerted);
-               if (*alerted)
+               if (*alerted) {
+                       mono_w32handle_unref (handle);
                        return 0;
-               mono_w32handle_ref (handle);
+               }
        }
 
        res = mono_w32handle_timedwait_signal_naked (&handle_data->signal_cond, &handle_data->signal_mutex, timeout, poll, alerted);