[Spice-devel] [spice-gtk 3/3] gio-coroutine: Fix leak in corner case

Christophe Fergeau cfergeau at redhat.com
Mon Feb 23 02:55:48 PST 2015


When delayed emissions of a signal or a notification is queued in an
idle, but the coroutine is re-inited before the idle gets a chance to
run, the idle is now removed after warning about it, but the object
instance which was referenced as part of the signal/notify delayed
emission is never released, causing a leak.
This commit uses g_idle_add_full in order to properly release the object
when the idle is removed.

In order for this to work properly, the coroutine_yieldto call must be
moved from the idle callback to the GDestroyNotify callback. Before that
commit, through coroutine switching magic, we return from the idle
callback long after the g_coroutine_* method which queued it returned.
The GDestroyNotify callback would thus get a pointer to invalid memory
wehn it gets to run (after the idle returns).
---
 gtk/gio-coroutine.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/gtk/gio-coroutine.c b/gtk/gio-coroutine.c
index 7527138..dc8e05f 100644
--- a/gtk/gio-coroutine.c
+++ b/gtk/gio-coroutine.c
@@ -202,12 +202,21 @@ static gboolean emit_main_context(gpointer opaque)
                          signal->detail, signal->var_args);
     signal->notified = TRUE;
 
-    coroutine_yieldto(signal->caller, NULL);
 
     return FALSE;
 }
 
 static void
+unref_instance(gpointer opaque)
+{
+    struct signal_data *data = opaque;
+
+    g_object_unref(data->instance);
+    if (data->notified)
+        coroutine_yieldto(data->caller, NULL);
+}
+
+static void
 run_in_idle(GSourceFunc idle_callback, gpointer opaque)
 {
     struct signal_data *data = opaque;
@@ -215,7 +224,9 @@ run_in_idle(GSourceFunc idle_callback, gpointer opaque)
     g_warn_if_fail(data->caller->idle_id == 0);
 
     g_object_ref(data->instance);
-    data->caller->idle_id = g_idle_add(idle_callback, data);
+    data->caller->idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
+                                            idle_callback, data,
+                                            unref_instance);
     /* This switches to the system coroutine context, lets
      * the idle function run to dispatch the signal, and
      * finally returns once complete. ie this is synchronous
@@ -228,7 +239,6 @@ run_in_idle(GSourceFunc idle_callback, gpointer opaque)
         g_source_remove(data->caller->idle_id);
     }
     data->caller->idle_id = 0;
-    g_object_unref(data->instance);
 }
 
 void
@@ -262,7 +272,6 @@ static gboolean notify_main_context(gpointer opaque)
     g_object_notify(signal->instance, signal->propname);
     signal->notified = TRUE;
 
-    coroutine_yieldto(signal->caller, NULL);
 
     return FALSE;
 }
-- 
2.1.0



More information about the Spice-devel mailing list