diff options
author | Ray Strode <rstrode@redhat.com> | 2023-03-27 11:18:40 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2023-03-27 15:27:39 -0400 |
commit | a6e627bf5797a812aebe90ad840b20a4950f064f (patch) | |
tree | 57167ada6ebb67ad253caf76f33c46b108eef8e9 | |
parent | 3ca35f267628cc80fa1299265e30bc6c9c742199 (diff) | |
download | accountsservice-a6e627bf5797a812aebe90ad840b20a4950f064f.tar.gz |
user-manager: Cope with buggy callers better
The user manager owns the users returned from
act_user_manager_get_user*, but it's possible callers may not realize
that.
If a caller does unref the result while a user fetch is in progress, it
can lead to crashes that are hard to pin back to the caller.
This commit adds a weak reference to the user object while fetch user
requests are in flight, and cancels those requests, if the user object
is unexpectantly destroyed in the meanwhile.
-rw-r--r-- | src/libaccountsservice/act-user-manager.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c index 6426a63..fe042a1 100644 --- a/src/libaccountsservice/act-user-manager.c +++ b/src/libaccountsservice/act-user-manager.c @@ -230,6 +230,7 @@ static void fetch_user_incrementally (ActUserManagerFetchUserRequest *reques static void maybe_set_is_loaded (ActUserManager *manager); static void update_user (ActUserManager *manager, ActUser *user); +static void free_fetch_user_request (ActUserManagerFetchUserRequest *request); static gpointer user_manager_object = NULL; G_DEFINE_TYPE_WITH_PRIVATE (ActUserManager, act_user_manager, G_TYPE_OBJECT) @@ -708,6 +709,33 @@ set_has_multiple_users (ActUserManager *manager, } } +static void +on_user_destroyed (ActUserManager *manager, + GObject *destroyed_user) +{ + ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager); + GSList *node; + + node = priv->fetch_user_requests; + while (node != NULL) { + ActUserManagerFetchUserRequest *request; + GSList *next_node; + + request = node->data; + next_node = node->next; + + if ((gpointer) request->user == destroyed_user) { + g_debug ("ActUserManager: User %s destroyed while still being fetched", + request->description); + + request->user = NULL; + free_fetch_user_request (request); + } + + node = next_node; + } +} + /* (transfer full) */ static ActUser * create_new_user (ActUserManager *manager) @@ -1736,7 +1764,10 @@ free_fetch_user_request (ActUserManagerFetchUserRequest *request) ActUserManager *manager = request->manager; ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager); - g_object_set_data (G_OBJECT (request->user), "fetch-user-request", NULL); + if (request->user != NULL) { + g_object_set_data (G_OBJECT (request->user), "fetch-user-request", NULL); + g_object_weak_unref (G_OBJECT (request->user), (GWeakNotify) on_user_destroyed, manager); + } priv->fetch_user_requests = g_slist_remove (priv->fetch_user_requests, request); if (request->type == ACT_USER_MANAGER_FETCH_USER_FROM_USERNAME_REQUEST) { @@ -1749,6 +1780,7 @@ free_fetch_user_request (ActUserManagerFetchUserRequest *request) g_cancellable_cancel (request->cancellable); g_object_unref (request->cancellable); + g_debug ("ActUserManager: unrefing manager owned by fetch user request"); g_object_unref (manager); @@ -1860,6 +1892,7 @@ fetch_user_with_username_from_accounts_service (ActUserManager *manager, priv->fetch_user_requests = g_slist_prepend (priv->fetch_user_requests, request); g_object_set_data (G_OBJECT (user), "fetch-user-request", request); + g_object_weak_ref (G_OBJECT (user), (GWeakNotify) on_user_destroyed, manager); fetch_user_incrementally (request); } @@ -1884,6 +1917,7 @@ fetch_user_with_id_from_accounts_service (ActUserManager *manager, priv->fetch_user_requests = g_slist_prepend (priv->fetch_user_requests, request); g_object_set_data (G_OBJECT (user), "fetch-user-request", request); + g_object_weak_ref (G_OBJECT (user), (GWeakNotify) on_user_destroyed, manager); fetch_user_incrementally (request); } |