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.
This commit is contained in:
Benjamin Berg 2021-04-22 17:24:07 +02:00
parent 511d456006
commit 94e86875ae

View file

@ -53,6 +53,8 @@ typedef struct
GUsbContext *usb_ctx; GUsbContext *usb_ctx;
GCancellable *cancellable; GCancellable *cancellable;
GSList *sources;
gint pending_devices; gint pending_devices;
gboolean enumerated; gboolean enumerated;
@ -102,6 +104,7 @@ typedef struct
{ {
FpContext *context; FpContext *context;
FpDevice *device; FpDevice *device;
GSource *source;
} RemoveDeviceData; } RemoveDeviceData;
static gboolean 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_signal_emit (data->context, signals[DEVICE_REMOVED_SIGNAL], 0, data->device);
g_ptr_array_remove_index_fast (priv->devices, idx); g_ptr_array_remove_index_fast (priv->devices, idx);
g_free (data);
return G_SOURCE_REMOVE; 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 static void
remove_device (FpContext *context, FpDevice *device) remove_device (FpContext *context, FpDevice *device)
{ {
g_autoptr(GSource) source = NULL;
FpContextPrivate *priv = fp_context_get_instance_private (context);
RemoveDeviceData *data; RemoveDeviceData *data;
data = g_new (RemoveDeviceData, 1); data = g_new (RemoveDeviceData, 1);
data->context = context; data->context = context;
data->device = device; 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 static void
@ -284,6 +302,8 @@ fp_context_finalize (GObject *object)
g_clear_object (&priv->cancellable); g_clear_object (&priv->cancellable);
g_clear_pointer (&priv->drivers, g_array_unref); 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) if (priv->usb_ctx)
g_object_run_dispose (G_OBJECT (priv->usb_ctx)); g_object_run_dispose (G_OBJECT (priv->usb_ctx));
g_clear_object (&priv->usb_ctx); g_clear_object (&priv->usb_ctx);