[gnome-desktop] IdleMonitor: protect watches from being freed while in flight



commit 91727625fc92c5f44208c3d540ca6e12157a68d6
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Tue Sep 3 18:39:04 2013 +0200

    IdleMonitor: protect watches from being freed while in flight
    
    If you added an idle watch and then immediately removed it, it
    was possible that the watch was freed before the dbus call was
    handled by mutter, thus causing a crash later one.
    Prevent that by reference counting the watch structures.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707396

 libgnome-desktop/gnome-idle-monitor.c |   39 +++++++++++++++++++++++++++++---
 1 files changed, 35 insertions(+), 4 deletions(-)
---
diff --git a/libgnome-desktop/gnome-idle-monitor.c b/libgnome-desktop/gnome-idle-monitor.c
index 721bba1..6af1343 100644
--- a/libgnome-desktop/gnome-idle-monitor.c
+++ b/libgnome-desktop/gnome-idle-monitor.c
@@ -48,6 +48,8 @@ struct _GnomeIdleMonitorPrivate
 
 typedef struct
 {
+       int                       ref_count;
+       gboolean                  dead;
        GnomeIdleMonitor         *monitor;
        guint                     id;
        guint                     upstream_id;
@@ -111,8 +113,12 @@ get_next_watch_serial (void)
 }
 
 static void
-idle_monitor_watch_free (GnomeIdleMonitorWatch *watch)
+idle_monitor_watch_unref (GnomeIdleMonitorWatch *watch)
 {
+       watch->ref_count--;
+       if (watch->ref_count)
+               return;
+
        if (watch->notify != NULL)
                watch->notify (watch->user_data);
 
@@ -124,6 +130,22 @@ idle_monitor_watch_free (GnomeIdleMonitorWatch *watch)
        g_slice_free (GnomeIdleMonitorWatch, watch);
 }
 
+static GnomeIdleMonitorWatch *
+idle_monitor_watch_ref (GnomeIdleMonitorWatch *watch)
+{
+       g_assert (watch->ref_count > 0);
+
+       watch->ref_count++;
+       return watch;
+}
+
+static void
+idle_monitor_watch_destroy (GnomeIdleMonitorWatch *watch)
+{
+       watch->dead = TRUE;
+       idle_monitor_watch_unref (watch);
+}
+
 static void
 gnome_idle_monitor_dispose (GObject *object)
 {
@@ -343,7 +365,7 @@ gnome_idle_monitor_init (GnomeIdleMonitor *monitor)
        monitor->priv->watches = g_hash_table_new_full (NULL,
                                                        NULL,
                                                        NULL,
-                                                       (GDestroyNotify)idle_monitor_watch_free);
+                                                       (GDestroyNotify)idle_monitor_watch_destroy);
        monitor->priv->watches_by_upstream_id = g_hash_table_new (NULL, NULL);
 
        monitor->priv->cancellable = g_cancellable_new ();
@@ -390,6 +412,7 @@ make_watch (GnomeIdleMonitor          *monitor,
        GnomeIdleMonitorWatch *watch;
 
        watch = g_slice_new0 (GnomeIdleMonitorWatch);
+       watch->ref_count = 1;
        watch->id = get_next_watch_serial ();
        watch->monitor = monitor;
        watch->callback = callback;
@@ -415,11 +438,18 @@ on_watch_added (GObject      *object,
        if (!res) {
                if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
                        g_error_free (error);
+                       idle_monitor_watch_unref (watch);
                        return;
                }
 
                g_warning ("Failed to acquire idle monitor proxy: %s", error->message);
                g_error_free (error);
+               idle_monitor_watch_unref (watch);
+               return;
+       }
+
+       if (watch->dead) {
+               idle_monitor_watch_unref (watch);
                return;
        }
 
@@ -429,6 +459,7 @@ on_watch_added (GObject      *object,
 
        g_hash_table_insert (monitor->priv->watches_by_upstream_id,
                             GINT_TO_POINTER (watch->upstream_id), watch);
+       idle_monitor_watch_unref (watch);
 }
 
 static void
@@ -438,7 +469,7 @@ add_idle_watch (GnomeIdleMonitor      *monitor,
        meta_dbus_idle_monitor_call_add_idle_watch (monitor->priv->proxy,
                                                    watch->timeout_msec,
                                                    monitor->priv->cancellable,
-                                                   on_watch_added, watch);
+                                                   on_watch_added, idle_monitor_watch_ref (watch));
 }
 
 static void
@@ -447,7 +478,7 @@ add_active_watch (GnomeIdleMonitor      *monitor,
 {
        meta_dbus_idle_monitor_call_add_user_active_watch (monitor->priv->proxy,
                                                           monitor->priv->cancellable,
-                                                          on_watch_added, watch);
+                                                          on_watch_added, idle_monitor_watch_ref (watch));
 }
 
 /**


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]