gmain: handle blocked source in g_source_add_child_source()
authorWim Taymans <wim.taymans@collabora.co.uk>
Thu, 30 May 2013 14:46:02 +0000 (16:46 +0200)
committerDan Winship <danw@gnome.org>
Tue, 25 Jun 2013 13:25:57 +0000 (09:25 -0400)
When a child_source is added to a blocked source it has no context, yet we
call block_source on it that segfaults when it dereferences the NULL context
when it attempts to remove the file descriptors. To fix this we:

- Ensure that when we block a source, we don't attempt to remove its file
  descriptors from a NULL context.

- Also ensure that when we attach a blocked source to a context, we don't add the
  file descriptors to the context.

https://bugzilla.gnome.org/show_bug.cgi?id=701283

glib/gmain.c

index cf219fe3c204f160b497493192b2ec5a2a2c4e95..3c6610855c8c887d941643049c2784bdcb9bd12d 100644 (file)
@@ -1118,15 +1118,18 @@ g_source_attach_unlocked (GSource      *source,
   source->ref_count++;
   source_add_to_context (source, context);
 
-  tmp_list = source->poll_fds;
-  while (tmp_list)
+  if (!SOURCE_BLOCKED (source))
     {
-      g_main_context_add_poll_unlocked (context, source->priority, tmp_list->data);
-      tmp_list = tmp_list->next;
-    }
+      tmp_list = source->poll_fds;
+      while (tmp_list)
+        {
+          g_main_context_add_poll_unlocked (context, source->priority, tmp_list->data);
+          tmp_list = tmp_list->next;
+        }
 
-  for (tmp_list = source->priv->fds; tmp_list; tmp_list = tmp_list->next)
-    g_main_context_add_poll_unlocked (context, source->priority, tmp_list->data);
+      for (tmp_list = source->priv->fds; tmp_list; tmp_list = tmp_list->next)
+        g_main_context_add_poll_unlocked (context, source->priority, tmp_list->data);
+    }
 
   tmp_list = source->priv->child_sources;
   while (tmp_list)
@@ -2941,15 +2944,18 @@ block_source (GSource *source)
 
   source->flags |= G_SOURCE_BLOCKED;
 
-  tmp_list = source->poll_fds;
-  while (tmp_list)
+  if (source->context)
     {
-      g_main_context_remove_poll_unlocked (source->context, tmp_list->data);
-      tmp_list = tmp_list->next;
-    }
+      tmp_list = source->poll_fds;
+      while (tmp_list)
+        {
+          g_main_context_remove_poll_unlocked (source->context, tmp_list->data);
+          tmp_list = tmp_list->next;
+        }
 
-  for (tmp_list = source->priv->fds; tmp_list; tmp_list = tmp_list->next)
-    g_main_context_remove_poll_unlocked (source->context, tmp_list->data);
+      for (tmp_list = source->priv->fds; tmp_list; tmp_list = tmp_list->next)
+        g_main_context_remove_poll_unlocked (source->context, tmp_list->data);
+    }
 
   if (source->priv && source->priv->child_sources)
     {