From 5e57af62866b4d24c68b72b3467797e72de391bd Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Mon, 11 Jan 2016 17:04:11 +0100 Subject: [PATCH] idle-monitor-native: Don't leak user active watches This fixes an issue analogous to bug 760330 for the X11 backend, except on this backend we wouldn't crash accessing free'd memory. Instead we're leaking watches since we steal them from the hash table which means that when they're removed in _meta_idle_monitor_watch_fire() they're no longer there and thus they're never free'd. https://bugzilla.gnome.org/show_bug.cgi?id=760476 --- .../native/meta-idle-monitor-native.c | 68 +++++++------------ 1 file changed, 24 insertions(+), 44 deletions(-) diff --git a/src/backends/native/meta-idle-monitor-native.c b/src/backends/native/meta-idle-monitor-native.c index 13d8d516f..da1ad06d1 100644 --- a/src/backends/native/meta-idle-monitor-native.c +++ b/src/backends/native/meta-idle-monitor-native.c @@ -164,56 +164,36 @@ meta_idle_monitor_native_init (MetaIdleMonitorNative *monitor_native) monitor->watches = g_hash_table_new_full (NULL, NULL, NULL, free_watch); } -typedef struct { - MetaIdleMonitorNative *monitor_native; - GList *fired_watches; -} CheckNativeClosure; - -static gboolean -check_native_watch (gpointer key, - gpointer value, - gpointer user_data) -{ - MetaIdleMonitorWatchNative *watch_native = value; - MetaIdleMonitorWatch *watch = (MetaIdleMonitorWatch *) watch_native; - CheckNativeClosure *closure = user_data; - gboolean steal; - - if (watch->timeout_msec == 0) - { - closure->fired_watches = g_list_prepend (closure->fired_watches, watch); - steal = TRUE; - } - else - { - g_source_set_ready_time (watch_native->timeout_source, - closure->monitor_native->last_event_time + - watch->timeout_msec * 1000); - steal = FALSE; - } - - return steal; -} - -static void -fire_native_watch (gpointer watch, - gpointer data) -{ - _meta_idle_monitor_watch_fire (watch); -} - void meta_idle_monitor_native_reset_idletime (MetaIdleMonitor *monitor) { MetaIdleMonitorNative *monitor_native = META_IDLE_MONITOR_NATIVE (monitor); - CheckNativeClosure closure; + GList *node, *watch_ids; monitor_native->last_event_time = g_get_monotonic_time (); - closure.monitor_native = monitor_native; - closure.fired_watches = NULL; - g_hash_table_foreach_steal (monitor->watches, check_native_watch, &closure); + watch_ids = g_hash_table_get_keys (monitor->watches); - g_list_foreach (closure.fired_watches, fire_native_watch, NULL); - g_list_free (closure.fired_watches); + for (node = watch_ids; node != NULL; node = node->next) + { + guint watch_id = GPOINTER_TO_UINT (node->data); + MetaIdleMonitorWatchNative *watch; + + watch = g_hash_table_lookup (monitor->watches, GUINT_TO_POINTER (watch_id)); + if (!watch) + continue; + + if (watch->base.timeout_msec == 0) + { + _meta_idle_monitor_watch_fire ((MetaIdleMonitorWatch *) watch); + } + else + { + g_source_set_ready_time (watch->timeout_source, + monitor_native->last_event_time + + watch->base.timeout_msec * 1000); + } + } + + g_list_free (watch_ids); }