summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2023-03-27 11:24:02 -0400
committerRay Strode <rstrode@redhat.com>2023-03-27 15:27:17 -0400
commit485b10740e46702952aeacafe0cf94bf8cc21f2e (patch)
treefd1f5f1794a9da91a906f864d9164abf646d4d34
parent24645afea0da48496914614b4c0f0ab1d3d743d5 (diff)
downloadaccountsservice-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.c14
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;