From 63873c0eb114faf6696874fe577912af687d67cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 21 Apr 2021 06:17:36 +0200 Subject: [PATCH] application: Unset the registered state after shutting down An application that has been shut down is still marked as registered even if its implementation has been already destroyed. This may lead to unguarded crashes when calling functions that have assumptions for being used with registered applications. So, when an application is registered, mark it as unregistered just before destroying its implementation and after being shut down, so that we follow the registration process in reversed order. Added tests --- gio/gapplication.c | 7 ++++ gio/tests/gapplication.c | 76 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/gio/gapplication.c b/gio/gapplication.c index 8e6517635..bf4a4cb65 100644 --- a/gio/gapplication.c +++ b/gio/gapplication.c @@ -2578,6 +2578,13 @@ g_application_run (GApplication *application, if (application->priv->impl) { + if (application->priv->is_registered) + { + application->priv->is_registered = FALSE; + + g_object_notify (G_OBJECT (application), "is-registered"); + } + g_application_impl_flush (application->priv->impl); g_application_impl_destroy (application->priv->impl); application->priv->impl = NULL; diff --git a/gio/tests/gapplication.c b/gio/tests/gapplication.c index 900e7ac97..6f1a27e0f 100644 --- a/gio/tests/gapplication.c +++ b/gio/tests/gapplication.c @@ -576,6 +576,81 @@ test_quit (void) g_free (binpath); } +typedef struct +{ + gboolean shutdown; + GParamSpec *notify_spec; /* (owned) (nullable) */ +} RegisteredData; + +static void +on_registered_shutdown (GApplication *app, + gpointer user_data) +{ + RegisteredData *registered_data = user_data; + + registered_data->shutdown = TRUE; +} + +static void +on_registered_notify (GApplication *app, + GParamSpec *spec, + gpointer user_data) +{ + RegisteredData *registered_data = user_data; + registered_data->notify_spec = g_param_spec_ref (spec); + + if (g_application_get_is_registered (app)) + g_assert_false (registered_data->shutdown); + else + g_assert_true (registered_data->shutdown); +} + +static void +test_registered (void) +{ + char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL); + gchar *argv[] = { binpath, NULL }; + RegisteredData registered_data = { FALSE, NULL }; + GApplication *app; + + app = g_application_new (NULL, G_APPLICATION_FLAGS_NONE); + g_signal_connect (app, "activate", G_CALLBACK (noappid_activate), NULL); + g_signal_connect (app, "shutdown", G_CALLBACK (on_registered_shutdown), ®istered_data); + g_signal_connect (app, "notify::is-registered", G_CALLBACK (on_registered_notify), ®istered_data); + + g_assert_null (registered_data.notify_spec); + + g_assert_true (g_application_register (app, NULL, NULL)); + g_assert_true (g_application_get_is_registered (app)); + + g_assert_nonnull (registered_data.notify_spec); + g_assert_cmpstr (registered_data.notify_spec->name, ==, "is-registered"); + g_clear_pointer (®istered_data.notify_spec, g_param_spec_unref); + + g_assert_false (registered_data.shutdown); + + g_application_run (app, 1, argv); + + g_assert_true (registered_data.shutdown); + g_assert_false (g_application_get_is_registered (app)); + g_assert_nonnull (registered_data.notify_spec); + g_assert_cmpstr (registered_data.notify_spec->name, ==, "is-registered"); + g_clear_pointer (®istered_data.notify_spec, g_param_spec_unref); + + /* Register it again */ + registered_data.shutdown = FALSE; + g_assert_true (g_application_register (app, NULL, NULL)); + g_assert_true (g_application_get_is_registered (app)); + g_assert_nonnull (registered_data.notify_spec); + g_assert_cmpstr (registered_data.notify_spec->name, ==, "is-registered"); + g_clear_pointer (®istered_data.notify_spec, g_param_spec_unref); + g_assert_false (registered_data.shutdown); + + g_object_unref (app); + + g_free (binpath); +} + static void on_activate (GApplication *app) { @@ -1136,6 +1211,7 @@ main (int argc, char **argv) g_test_add_func ("/gapplication/properties", properties); g_test_add_func ("/gapplication/app-id", appid); g_test_add_func ("/gapplication/quit", test_quit); + g_test_add_func ("/gapplication/registered", test_registered); g_test_add_func ("/gapplication/local-actions", test_local_actions); /* g_test_add_func ("/gapplication/remote-actions", test_remote_actions); */ g_test_add_func ("/gapplication/local-command-line", test_local_command_line);