From 1b8835e15b09a2cb7b87edb7cc7c3fc37c33815b Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 31 Jul 2014 09:21:05 -0400 Subject: [PATCH] libnm-glib: fix a crash when using multiple NMClients NMObjectCache was assuming there would never be more than one object with the same path, but since NMClient is an NMObject, it was getting cached too, so if you created two clients and then unreffed one of them, it's possible the wrong one could get left in the cache, causing a crash the next time the other one called nm_object_cache_clear(). Fix this by only adding NMObjects to the cache in the codepaths where we also check to see if the object was already in the cache. (This also means we can remove the "except" argument to nm_object_cache_clear(), since the NMClient won't be cached any more.) (cherry picked from commit fe264a2d01245d1cc814f5df6f86623bb8b35aef) --- libnm-glib/nm-client.c | 2 +- libnm-glib/nm-object-cache.c | 26 +++++++++++++------------- libnm-glib/nm-object-cache.h | 2 +- libnm-glib/nm-object.c | 6 ++++-- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/libnm-glib/nm-client.c b/libnm-glib/nm-client.c index 9e6ba09e61..0aadc80406 100644 --- a/libnm-glib/nm-client.c +++ b/libnm-glib/nm-client.c @@ -1385,7 +1385,7 @@ proxy_name_owner_changed (DBusGProxy *proxy, /* Clear object cache to ensure bad refcounting by clients doesn't * keep objects in the cache. */ - _nm_object_cache_clear (NM_OBJECT (client)); + _nm_object_cache_clear (); } else { _nm_object_suppress_property_updates (NM_OBJECT (client), FALSE); _nm_object_reload_properties_async (NM_OBJECT (client), updated_properties, client); diff --git a/libnm-glib/nm-object-cache.c b/libnm-glib/nm-object-cache.c index 2748b1df3a..6d188f3ead 100644 --- a/libnm-glib/nm-object-cache.c +++ b/libnm-glib/nm-object-cache.c @@ -65,27 +65,27 @@ _nm_object_cache_get (const char *path) } void -_nm_object_cache_clear (NMObject *except) +_nm_object_cache_clear (void) { GHashTableIter iter; - NMObject *obj; + GObject *obj; const char *path; char *foo; - _init_cache (); + if (!cache) + return; + g_hash_table_iter_init (&iter, cache); while (g_hash_table_iter_next (&iter, (gpointer) &path, (gpointer) &obj)) { - if (obj != except) { - /* Remove the callback so that if the object isn't yet released - * by a client, when it does finally get unrefed, it won't trigger - * the cache removal for a new object with the same path as the - * one being released. - */ - foo = g_object_steal_data (G_OBJECT (obj), "nm-object-cache-tag"); - g_free (foo); + /* Remove the callback so that if the object isn't yet released + * by a client, when it does finally get unrefed, it won't trigger + * the cache removal for a new object with the same path as the + * one being released. + */ + foo = g_object_steal_data (obj, "nm-object-cache-tag"); + g_free (foo); - g_hash_table_iter_remove (&iter); - } + g_hash_table_iter_remove (&iter); } } diff --git a/libnm-glib/nm-object-cache.h b/libnm-glib/nm-object-cache.h index 84752134bc..14b43571e3 100644 --- a/libnm-glib/nm-object-cache.h +++ b/libnm-glib/nm-object-cache.h @@ -32,7 +32,7 @@ G_BEGIN_DECLS /* Returns referenced object from the cache */ NMObject *_nm_object_cache_get (const char *path); void _nm_object_cache_add (NMObject *object); -void _nm_object_cache_clear (NMObject *except); +void _nm_object_cache_clear (void); G_END_DECLS diff --git a/libnm-glib/nm-object.c b/libnm-glib/nm-object.c index 61282cfbe9..184f980d31 100644 --- a/libnm-glib/nm-object.c +++ b/libnm-glib/nm-object.c @@ -159,8 +159,6 @@ constructor (GType type, return NULL; } - _nm_object_cache_add (NM_OBJECT (object)); - return object; } @@ -578,6 +576,8 @@ _nm_object_create (GType type, DBusGConnection *connection, const char *path) NM_OBJECT_DBUS_CONNECTION, connection, NM_OBJECT_DBUS_PATH, path, NULL); + if (NM_IS_OBJECT (object)) + _nm_object_cache_add (NM_OBJECT (object)); if (!g_initable_init (G_INITABLE (object), NULL, &error)) { dbgmsg ("Could not create object for %s: %s", path, error->message); g_error_free (error); @@ -661,6 +661,8 @@ async_got_type (GType type, gpointer user_data) NM_OBJECT_DBUS_PATH, async_data->path, NULL); g_warn_if_fail (object != NULL); + if (NM_IS_OBJECT (object)) + _nm_object_cache_add (NM_OBJECT (object)); g_async_initable_init_async (G_ASYNC_INITABLE (object), G_PRIORITY_DEFAULT, NULL, async_inited, async_data); }