summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Catanzaro <mcatanzaro@redhat.com>2023-04-25 19:17:22 -0500
committerMichael Catanzaro <mcatanzaro@redhat.com>2023-04-27 09:20:48 -0500
commit0e205fce5fbfa8f2c6f6ac0acc890311ff333d04 (patch)
tree5024eb2e234f1d10d72cfa6265f7f5d31e7fbd54
parentecb788d44e5c4f01234b7b02141c2779373957c5 (diff)
downloadlibsecret-0e205fce5fbfa8f2c6f6ac0acc890311ff333d04.tar.gz
file-backend: avoid deadlock when portal op is canceledmcatanzaro/cancellable-deadlock
Calling g_cancellable_disconnect() inside a cancelled handler is a guaranteed deadlock. Cancellables should only be canceled once, so we don't need to worry about a second cancellation occurring. I think it's sufficent to disconnect when the InitClosure is freed. Fixes #86
-rw-r--r--libsecret/secret-file-backend.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/libsecret/secret-file-backend.c b/libsecret/secret-file-backend.c
index 12738df..dd18a5b 100644
--- a/libsecret/secret-file-backend.c
+++ b/libsecret/secret-file-backend.c
@@ -206,6 +206,7 @@ typedef struct {
GDBusConnection *connection;
gchar *request_path;
guint portal_signal_id;
+ GCancellable *cancellable;
gulong cancellable_signal_id;
} InitClosure;
@@ -218,6 +219,14 @@ init_closure_free (gpointer data)
g_clear_pointer (&init->buffer, egg_secure_free);
g_clear_object (&init->connection);
g_clear_pointer (&init->request_path, g_free);
+ if (init->cancellable_signal_id) {
+ g_cancellable_disconnect (init->cancellable, init->cancellable_signal_id);
+ init->cancellable_signal_id = 0;
+ }
+ /* Note: do not cancel the cancellable here! That's for the API user to
+ * do. We're just keeping track of it here so we can disconnect.
+ */
+ g_clear_object (&init->cancellable);
g_free (init);
}
@@ -352,9 +361,6 @@ on_portal_cancel (GCancellable *cancellable,
cancellable,
on_portal_request_close,
task);
-
- g_cancellable_disconnect (cancellable, init->cancellable_signal_id);
- init->cancellable_signal_id = 0;
}
static void
@@ -575,6 +581,7 @@ secret_file_backend_real_init_async (GAsyncInitable *initable,
init = g_new0 (InitClosure, 1);
init->io_priority = io_priority;
init->file = file;
+ init->cancellable = g_object_ref (cancellable);
g_task_set_task_data (task, init, init_closure_free);
g_bus_get (G_BUS_TYPE_SESSION, cancellable, on_bus_get, task);
} else {