diff options
author | Ray Strode <rstrode@redhat.com> | 2023-03-27 11:24:02 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2023-03-27 15:27:17 -0400 |
commit | 485b10740e46702952aeacafe0cf94bf8cc21f2e (patch) | |
tree | fd1f5f1794a9da91a906f864d9164abf646d4d34 | |
parent | 24645afea0da48496914614b4c0f0ab1d3d743d5 (diff) | |
download | accountsservice-485b10740e46702952aeacafe0cf94bf8cc21f2e.tar.gz |
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
-rw-r--r-- | src/libaccountsservice/act-user-manager.c | 14 |
1 files changed, 14 insertions, 0 deletions
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; |