gactiongroupexporter: Fix memory problems on an error handling path

Almost identically to the previous commit, fix a similar latent bug in
`g_dbus_connection_export_action_group()`, which was not ready to handle
the fledgling `GActionGroupExporter` being freed early on an error
handling path.

See the previous commit message for details of the approach.

This includes a unit test.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Fixes: #3366
This commit is contained in:
Philip Withnall 2024-05-15 14:00:09 +01:00
parent df2c5d925a
commit 7a7137838e
No known key found for this signature in database
GPG Key ID: DCDF5885B1F3ED73
2 changed files with 56 additions and 20 deletions

View File

@ -531,10 +531,8 @@ org_gtk_Actions_method_call (GDBusConnection *connection,
}
static void
g_action_group_exporter_free (gpointer user_data)
g_action_group_exporter_free (GActionGroupExporter *exporter)
{
GActionGroupExporter *exporter = user_data;
g_signal_handlers_disconnect_by_func (exporter->action_group,
g_action_group_exporter_action_added, exporter);
g_signal_handlers_disconnect_by_func (exporter->action_group,
@ -616,15 +614,6 @@ g_dbus_connection_export_action_group (GDBusConnection *connection,
}
exporter = g_slice_new (GActionGroupExporter);
id = g_dbus_connection_register_object (connection, object_path, org_gtk_Actions, &vtable,
exporter, g_action_group_exporter_free, error);
if (id == 0)
{
g_slice_free (GActionGroupExporter, exporter);
return 0;
}
exporter->context = g_main_context_ref_thread_default ();
exporter->pending_changes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
exporter->pending_source = NULL;
@ -632,14 +621,20 @@ g_dbus_connection_export_action_group (GDBusConnection *connection,
exporter->connection = g_object_ref (connection);
exporter->object_path = g_strdup (object_path);
g_signal_connect (action_group, "action-added",
G_CALLBACK (g_action_group_exporter_action_added), exporter);
g_signal_connect (action_group, "action-removed",
G_CALLBACK (g_action_group_exporter_action_removed), exporter);
g_signal_connect (action_group, "action-state-changed",
G_CALLBACK (g_action_group_exporter_action_state_changed), exporter);
g_signal_connect (action_group, "action-enabled-changed",
G_CALLBACK (g_action_group_exporter_action_enabled_changed), exporter);
id = g_dbus_connection_register_object (connection, object_path, org_gtk_Actions, &vtable,
exporter, (GDestroyNotify) g_action_group_exporter_free, error);
if (id != 0)
{
g_signal_connect (action_group, "action-added",
G_CALLBACK (g_action_group_exporter_action_added), exporter);
g_signal_connect (action_group, "action-removed",
G_CALLBACK (g_action_group_exporter_action_removed), exporter);
g_signal_connect (action_group, "action-state-changed",
G_CALLBACK (g_action_group_exporter_action_state_changed), exporter);
g_signal_connect (action_group, "action-enabled-changed",
G_CALLBACK (g_action_group_exporter_action_enabled_changed), exporter);
}
return id;
}

View File

@ -1125,6 +1125,46 @@ test_dbus_export (void)
session_bus_down ();
}
static void
test_dbus_export_error_handling (void)
{
GDBusConnection *bus = NULL;
GSimpleActionGroup *group = NULL;
GError *local_error = NULL;
guint id1, id2;
g_test_summary ("Test that error handling of action group export failure works");
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3366");
session_bus_up ();
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
group = g_simple_action_group_new ();
g_simple_action_group_add_entries (group,
exported_entries,
G_N_ELEMENTS (exported_entries),
NULL);
id1 = g_dbus_connection_export_action_group (bus, "/", G_ACTION_GROUP (group), &local_error);
g_assert_no_error (local_error);
g_assert_cmpuint (id1, !=, 0);
/* Trigger a failure by trying to export on a path which is already in use */
id2 = g_dbus_connection_export_action_group (bus, "/", G_ACTION_GROUP (group), &local_error);
g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS);
g_assert_cmpuint (id2, ==, 0);
g_clear_error (&local_error);
g_dbus_connection_unexport_action_group (bus, id1);
while (g_main_context_iteration (NULL, FALSE));
g_object_unref (group);
g_object_unref (bus);
session_bus_down ();
}
static gpointer
do_export (gpointer data)
{
@ -1448,6 +1488,7 @@ main (int argc, char **argv)
g_test_add_func ("/actions/entries", test_entries);
g_test_add_func ("/actions/parse-detailed", test_parse_detailed);
g_test_add_func ("/actions/dbus/export", test_dbus_export);
g_test_add_func ("/actions/dbus/export/error-handling", test_dbus_export_error_handling);
g_test_add_func ("/actions/dbus/threaded", test_dbus_threaded);
g_test_add_func ("/actions/dbus/bug679509", test_bug679509);
g_test_add_func ("/actions/property", test_property_actions);