From 94e86875ae1f26c821fd4fb4c4c689c7e9b3bcbd Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 22 Apr 2021 17:24:07 +0200 Subject: [PATCH] context: Remove idle sources and use thread local context libfprint uses the thread local context in almost all cases. Update FpContext to also use it and make sure that any sources are removed when the FpContext object is finalized. Otherwise we may run into use-after-free issues. --- libfprint/fp-context.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c index 2b40d73..fc0eb8d 100644 --- a/libfprint/fp-context.c +++ b/libfprint/fp-context.c @@ -53,6 +53,8 @@ typedef struct GUsbContext *usb_ctx; GCancellable *cancellable; + GSList *sources; + gint pending_devices; gboolean enumerated; @@ -102,6 +104,7 @@ typedef struct { FpContext *context; FpDevice *device; + GSource *source; } RemoveDeviceData; static gboolean @@ -115,21 +118,36 @@ remove_device_idle_cb (RemoveDeviceData *data) g_signal_emit (data->context, signals[DEVICE_REMOVED_SIGNAL], 0, data->device); g_ptr_array_remove_index_fast (priv->devices, idx); - g_free (data); - return G_SOURCE_REMOVE; } +static void +remove_device_data_free (RemoveDeviceData *data) +{ + FpContextPrivate *priv = fp_context_get_instance_private (data->context); + + priv->sources = g_slist_remove (priv->sources, data->source); + g_free (data); +} + static void remove_device (FpContext *context, FpDevice *device) { + g_autoptr(GSource) source = NULL; + FpContextPrivate *priv = fp_context_get_instance_private (context); RemoveDeviceData *data; data = g_new (RemoveDeviceData, 1); data->context = context; data->device = device; - g_idle_add ((GSourceFunc) remove_device_idle_cb, data); + source = data->source = g_idle_source_new (); + g_source_set_callback (source, + G_SOURCE_FUNC (remove_device_idle_cb), data, + (GDestroyNotify) remove_device_data_free); + g_source_attach (source, g_main_context_get_thread_default ()); + + priv->sources = g_slist_prepend (priv->sources, source); } static void @@ -284,6 +302,8 @@ fp_context_finalize (GObject *object) g_clear_object (&priv->cancellable); g_clear_pointer (&priv->drivers, g_array_unref); + g_slist_free_full (g_steal_pointer (&priv->sources), (GDestroyNotify) g_source_destroy); + if (priv->usb_ctx) g_object_run_dispose (G_OBJECT (priv->usb_ctx)); g_clear_object (&priv->usb_ctx);