From 485b10740e46702952aeacafe0cf94bf8cc21f2e Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 27 Mar 2023 11:24:02 -0400 Subject: user-manager: Don't prematurely free duplicate ActUser objects If act_user_manager_get_user_by_id is called twice in a row quickly for the same user, two ActUser objects get generated, each ultimately representing the same user. The second one to load gets freed because it's a duplicate. Freeing it is problematic though, because there still may be callers relying on it. This commit changes the code to track the object as a "doppleganger" instead of freeing it. Closes https://gitlab.freedesktop.org/accountsservice/accountsservice/-/issues/103 --- src/libaccountsservice/act-user-manager.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c index 3b1a774..213ca1a 100644 --- a/src/libaccountsservice/act-user-manager.c +++ b/src/libaccountsservice/act-user-manager.c @@ -168,6 +168,7 @@ typedef struct GSList *new_sessions; GSList *new_users; /* (element-type ActUser) (owned) */ GSList *new_users_inhibiting_load; /* (element-type ActUser) (unowned) */ + GSList *dopplegangers; GSList *fetch_user_requests; GSList *exclude_usernames; @@ -960,6 +961,15 @@ on_new_user_loaded (ActUser *user, add_user (manager, user); } else { _act_user_load_from_user (old_user, user); + + /* The same user had two pending loads (one by uid and one by username), and + * so there are now two objects representing the same user. We can't free + * either one because they both may be in use by callers, and they're both + * ostensbly owned by the user manager. Keep the first one to win + * as the "main" one and treat the leftover one as a doppleganger that we just + * track to clean up at dispose time. + */ + priv->dopplegangers = g_slist_prepend (priv->dopplegangers, g_object_ref (user)); } g_object_unref (user); @@ -2496,6 +2506,10 @@ act_user_manager_finalize (GObject *object) (GFunc) free_fetch_user_request, NULL); g_slist_free (priv->fetch_user_requests); + g_slist_foreach (priv->dopplegangers, + (GFunc) g_object_unref, NULL); + g_slist_free (priv->dopplegangers); + g_slist_free (priv->new_users_inhibiting_load); node = priv->new_users; -- cgit v1.2.1