From 0d688241b3f714905391af168d4533bd04e4a17f Mon Sep 17 00:00:00 2001 From: climashscape Date: Thu, 12 Nov 2026 22:00:58 +0800 Subject: [PATCH] status-icon: use a weak ref for the ListNames callback look_for_status_applet() passes a bare XAppStatusIcon pointer. The owning SnItem can be removed while ListNames is in flight and drops its ref, finalizing the icon; on_list_names_completed() then uses freed memory (g_bus_own_name_on_connection with a stale connection). Pass a GWeakRef wrapper and bail out if the icon is gone. --- libxapp/xapp-status-icon.c | 63 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/libxapp/xapp-status-icon.c b/libxapp/xapp-status-icon.c index 6450862..64f03db 100644 --- a/libxapp/xapp-status-icon.c +++ b/libxapp/xapp-status-icon.c @@ -120,6 +120,45 @@ static void use_gtk_status_icon (XAppStatusIcon *self); static void remove_icon_path_from_bus (XAppStatusIcon *self); static void hide_and_defer_unref_status_icon (XAppStatusIcon *self, GtkStatusIcon *status_icon); +/* Async callbacks must not keep the icon alive: the SnItem owning it may be + * removed while the call is in flight. A weak ref lets the callback detect + * that case instead of dereferencing freed memory. */ +typedef struct +{ + GWeakRef icon; +} XAppStatusIconAsyncRef; + +static XAppStatusIconAsyncRef * +xapp_status_icon_async_ref_new (XAppStatusIcon *icon) +{ + XAppStatusIconAsyncRef *async_ref = g_new0 (XAppStatusIconAsyncRef, 1); + + g_weak_ref_init (&async_ref->icon, G_OBJECT (icon)); + + return async_ref; +} + +static XAppStatusIcon * +xapp_status_icon_async_ref_get (XAppStatusIconAsyncRef *async_ref) +{ + XAppStatusIcon *icon = g_weak_ref_get (&async_ref->icon); + + if (icon == NULL) + { + g_weak_ref_clear (&async_ref->icon); + g_free (async_ref); + } + + return icon; +} + +static void +xapp_status_icon_async_ref_free (XAppStatusIconAsyncRef *async_ref) +{ + g_weak_ref_clear (&async_ref->icon); + g_free (async_ref); +} + static void cancellable_reset (XAppStatusIcon *self) { @@ -1326,7 +1365,8 @@ on_list_names_completed (GObject *source, GAsyncResult *res, gpointer user_data) { - XAppStatusIcon *self = XAPP_STATUS_ICON(user_data); + XAppStatusIconAsyncRef *async_ref = user_data; + XAppStatusIcon *self; GVariant *result; GVariantIter *iter; gchar *str; @@ -1338,6 +1378,18 @@ on_list_names_completed (GObject *source, result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); + self = xapp_status_icon_async_ref_get (async_ref); + + if (self == NULL) + { + if (error != NULL) + g_error_free (error); + + if (result != NULL) + g_variant_unref (result); + + return; + } if (error != NULL) { @@ -1352,6 +1404,8 @@ on_list_names_completed (GObject *source, } g_error_free (error); + g_object_unref (self); + xapp_status_icon_async_ref_free (async_ref); return; } @@ -1380,6 +1434,8 @@ on_list_names_completed (GObject *source, else { connect_with_status_applet (self); + g_object_unref (self); + xapp_status_icon_async_ref_free (async_ref); return; } @@ -1388,6 +1444,9 @@ on_list_names_completed (GObject *source, { use_gtk_status_icon (self); } + + g_object_unref (self); + xapp_status_icon_async_ref_free (async_ref); } static void @@ -1409,7 +1468,7 @@ look_for_status_applet (XAppStatusIcon *self) 3000, /* 3 secs */ self->priv->cancellable, on_list_names_completed, - self); + xapp_status_icon_async_ref_new (self)); } static void