GSocket – GSocketSource finalizing not threadsafe on Windows

The requested_conditions list access is not threadsafe. When passing
the socket ownership from a GSource callback to another thread, which
also creates a GSocketSource for the socket, it can happen that the
original GSocketSource is finalized at the same time as the new one
is created. This would cause inconsistencies in the requested_conditions
list and can cause assertions or completely undefined behaviour.

https://bugzilla.gnome.org/show_bug.cgi?id=705027
This commit is contained in:
Sebastian Dröge 2013-07-28 16:43:44 +02:00
parent b3b6aab007
commit ab6b7dbc2e

View File

@ -172,6 +172,7 @@ struct _GSocketPrivate
int current_errors; int current_errors;
int selected_events; int selected_events;
GList *requested_conditions; /* list of requested GIOCondition * */ GList *requested_conditions; /* list of requested GIOCondition * */
GMutex win32_source_lock;
#endif #endif
struct { struct {
@ -759,6 +760,7 @@ g_socket_finalize (GObject *object)
} }
g_assert (socket->priv->requested_conditions == NULL); g_assert (socket->priv->requested_conditions == NULL);
g_mutex_clear (&socket->priv->win32_source_lock);
#endif #endif
for (i = 0; i < RECV_ADDR_CACHE_SIZE; i++) for (i = 0; i < RECV_ADDR_CACHE_SIZE; i++)
@ -970,6 +972,7 @@ g_socket_init (GSocket *socket)
socket->priv->construct_error = NULL; socket->priv->construct_error = NULL;
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
socket->priv->event = WSA_INVALID_EVENT; socket->priv->event = WSA_INVALID_EVENT;
g_mutex_init (&socket->priv->win32_source_lock);
#endif #endif
} }
@ -3074,24 +3077,28 @@ static void
add_condition_watch (GSocket *socket, add_condition_watch (GSocket *socket,
GIOCondition *condition) GIOCondition *condition)
{ {
g_mutex_lock (&socket->priv->win32_source_lock);
g_assert (g_list_find (socket->priv->requested_conditions, condition) == NULL); g_assert (g_list_find (socket->priv->requested_conditions, condition) == NULL);
socket->priv->requested_conditions = socket->priv->requested_conditions =
g_list_prepend (socket->priv->requested_conditions, condition); g_list_prepend (socket->priv->requested_conditions, condition);
update_select_events (socket); update_select_events (socket);
g_mutex_unlock (&socket->priv->win32_source_lock);
} }
static void static void
remove_condition_watch (GSocket *socket, remove_condition_watch (GSocket *socket,
GIOCondition *condition) GIOCondition *condition)
{ {
g_mutex_lock (&socket->priv->win32_source_lock);
g_assert (g_list_find (socket->priv->requested_conditions, condition) != NULL); g_assert (g_list_find (socket->priv->requested_conditions, condition) != NULL);
socket->priv->requested_conditions = socket->priv->requested_conditions =
g_list_remove (socket->priv->requested_conditions, condition); g_list_remove (socket->priv->requested_conditions, condition);
update_select_events (socket); update_select_events (socket);
g_mutex_unlock (&socket->priv->win32_source_lock);
} }
static GIOCondition static GIOCondition