mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-13 14:05:05 +01:00
gdbusconnection: Fix double unref on timeout/cancel sending a message
This appears to fix an intermittent failure seen when sending a D-Bus message with either of a cancellable or a timeout set. In particular, I can reliably reproduce it with: ``` meson test gdbus-test-codegen-min-required-2-64 --repeat 10000 ``` It can be caught easily with asan when reproduced. Tracking down the location of the refcount mismatch was a little tricky, but was simplified by replacing a load of `g_object_ref (message)` calls with `g_dbus_message_copy (message, NULL)` to switch `GDBusMessage` handling to using copy semantics. This allowed asan to home in on where the refcount mismatch was happening. The problem was that `send_message_data_deliver_error()` takes ownership of the `GTask` passed to it, but the `send_message_with_replace_cancelled_idle_cb()` and `send_message_with_reply_timeout_cb()` functions which were calling it, were not passing in a strong reference as they should have. Another approach to fixing this would have been to change the transfer semantics of `send_message_data_deliver_error()` so it was `(transfer none)` on its `GTask`. That would probably have resulted in cleaner code, but would have been a lot harder to verify/review the fix, and easier to inadvertently introduce new bugs. The fact that the bug was only triggered by the cancellation and timeout callbacks explains why it was intermittent: these code paths are typically never hit, but the timeout path may sometimes be hit on a very slow test run. Signed-off-by: Philip Withnall <pwithnall@endlessos.org> Fixes: #1264
This commit is contained in:
parent
88fd3f0a76
commit
4900ea5215
@ -1822,7 +1822,7 @@ send_message_data_deliver_reply_unlocked (GTask *task,
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from a user thread, lock is not held */
|
/* Called from a user thread, lock is not held; @task is (transfer full) */
|
||||||
static void
|
static void
|
||||||
send_message_data_deliver_error (GTask *task,
|
send_message_data_deliver_error (GTask *task,
|
||||||
GQuark domain,
|
GQuark domain,
|
||||||
@ -1849,13 +1849,14 @@ send_message_data_deliver_error (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 gboolean
|
static gboolean
|
||||||
send_message_with_reply_cancelled_idle_cb (gpointer user_data)
|
send_message_with_reply_cancelled_idle_cb (gpointer user_data)
|
||||||
{
|
{
|
||||||
GTask *task = user_data;
|
GTask *task = user_data;
|
||||||
|
|
||||||
send_message_data_deliver_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
g_object_ref (task);
|
||||||
|
send_message_data_deliver_error (g_steal_pointer (&task), G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
||||||
_("Operation was cancelled"));
|
_("Operation was cancelled"));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1879,13 +1880,14 @@ send_message_with_reply_cancelled_cb (GCancellable *cancellable,
|
|||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* 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 gboolean
|
static gboolean
|
||||||
send_message_with_reply_timeout_cb (gpointer user_data)
|
send_message_with_reply_timeout_cb (gpointer user_data)
|
||||||
{
|
{
|
||||||
GTask *task = user_data;
|
GTask *task = user_data;
|
||||||
|
|
||||||
send_message_data_deliver_error (task, G_IO_ERROR, G_IO_ERROR_TIMED_OUT,
|
g_object_ref (task);
|
||||||
|
send_message_data_deliver_error (g_steal_pointer (&task), G_IO_ERROR, G_IO_ERROR_TIMED_OUT,
|
||||||
_("Timeout was reached"));
|
_("Timeout was reached"));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user