diff options
author | Philip Withnall <pwithnall@endlessos.org> | 2023-02-22 12:19:16 +0000 |
---|---|---|
committer | Philip Withnall <pwithnall@endlessos.org> | 2023-04-14 15:37:21 +0100 |
commit | b84ec21f9c4c57990309e691206582c589f59770 (patch) | |
tree | e010f56fa58b510003dbd899a44e6c99dd4514ce | |
parent | 08a4387678346caaa42b69e5e6e5995d48cd61c4 (diff) | |
download | glib-b84ec21f9c4c57990309e691206582c589f59770.tar.gz |
gdbusconnection: Rearrange refcount handling of map_method_serial_to_task
It already implicitly held a strong ref on its `GTask` values, but
didn’t have a free function set so that they would be automatically
unreffed on removal from the map.
This meant that the functions handling removals from the map,
`on_worker_closed()` (via `cancel_method_on_close()`) and
`send_message_with_reply_cleanup()` had to call unref once more than
they would otherwise.
In `send_message_with_reply_cleanup()`, this behaviour depended on
whether it was called with `remove == TRUE`. If not, it was `(transfer
none)` not `(transfer full)`. This led to bugs in its callers.
For example, this led to a direct leak in `cancel_method_on_close()`, as
it needed to remove tasks from `map_method_serial_to_task`, but called
`send_message_with_reply_cleanup(remove = FALSE)` and erroneously didn’t
call unref an additional time.
Try and simplify it all by setting a `GDestroyNotify` on
`map_method_serial_to_task`’s values, and making the refcount handling
of `send_message_with_reply_cleanup()` not be conditional on its
arguments.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1264
-rw-r--r-- | gio/gdbusconnection.c | 24 |
1 files changed, 12 insertions, 12 deletions
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c index 0cbfc66c1..f4bc21bb3 100644 --- a/gio/gdbusconnection.c +++ b/gio/gdbusconnection.c @@ -409,7 +409,7 @@ struct _GDBusConnection GDBusConnectionFlags flags; /* Map used for managing method replies, protected by @lock */ - GHashTable *map_method_serial_to_task; /* guint32 -> GTask* */ + GHashTable *map_method_serial_to_task; /* guint32 -> owned GTask* */ /* Maps used for managing signal subscription, protected by @lock */ GHashTable *map_rule_to_signal_data; /* match rule (gchar*) -> SignalData */ @@ -1061,7 +1061,7 @@ g_dbus_connection_init (GDBusConnection *connection) g_mutex_init (&connection->lock); g_mutex_init (&connection->init_lock); - connection->map_method_serial_to_task = g_hash_table_new (g_direct_hash, g_direct_equal); + connection->map_method_serial_to_task = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); connection->map_rule_to_signal_data = g_hash_table_new (g_str_hash, g_str_equal); @@ -1768,7 +1768,7 @@ send_message_data_free (SendMessageData *data) /* ---------------------------------------------------------------------------------------------------- */ -/* can be called from any thread with lock held; @task is (transfer full) */ +/* can be called from any thread with lock held; @task is (transfer none) */ static void send_message_with_reply_cleanup (GTask *task, gboolean remove) { @@ -1798,13 +1798,11 @@ send_message_with_reply_cleanup (GTask *task, gboolean remove) GUINT_TO_POINTER (data->serial)); g_warn_if_fail (removed); } - - g_object_unref (task); } /* ---------------------------------------------------------------------------------------------------- */ -/* Called from GDBus worker thread with lock held; @task is (transfer full). */ +/* Called from GDBus worker thread with lock held; @task is (transfer none). */ static void send_message_data_deliver_reply_unlocked (GTask *task, GDBusMessage *reply) @@ -1822,7 +1820,7 @@ send_message_data_deliver_reply_unlocked (GTask *task, ; } -/* Called from a user thread, lock is not held; @task is (transfer full) */ +/* Called from a user thread, lock is not held; @task is (transfer none) */ static void send_message_data_deliver_error (GTask *task, GQuark domain, @@ -1839,7 +1837,10 @@ send_message_data_deliver_error (GTask *task, return; } + /* Hold a ref on @task as send_message_with_reply_cleanup() will remove it + * from the task map and could end up dropping the last reference */ g_object_ref (task); + send_message_with_reply_cleanup (task, TRUE); CONNECTION_UNLOCK (connection); @@ -1855,8 +1856,7 @@ send_message_with_reply_cancelled_idle_cb (gpointer user_data) { GTask *task = user_data; - g_object_ref (task); - send_message_data_deliver_error (g_steal_pointer (&task), G_IO_ERROR, G_IO_ERROR_CANCELLED, + send_message_data_deliver_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Operation was cancelled")); return FALSE; } @@ -1886,8 +1886,7 @@ send_message_with_reply_timeout_cb (gpointer user_data) { GTask *task = user_data; - g_object_ref (task); - send_message_data_deliver_error (g_steal_pointer (&task), G_IO_ERROR, G_IO_ERROR_TIMED_OUT, + send_message_data_deliver_error (task, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, _("Timeout was reached")); return FALSE; } @@ -2391,7 +2390,8 @@ on_worker_message_about_to_be_sent (GDBusWorker *worker, return message; } -/* called with connection lock held, in GDBusWorker thread */ +/* called with connection lock held, in GDBusWorker thread + * @key, @value and @user_data are (transfer none) */ static gboolean cancel_method_on_close (gpointer key, gpointer value, gpointer user_data) { |