diff --git a/glib/gtester.c b/glib/gtester.c index 94cfba641..c48ecaf94 100644 --- a/glib/gtester.c +++ b/glib/gtester.c @@ -668,8 +668,8 @@ parse_args (gint *argc_p, } } /* collapse argv */ - e = 1; - for (i = 1; i < argc; i++) + e = 0; + for (i = 0; i < argc; i++) if (argv[i]) { argv[e++] = argv[i]; diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 27c72a416..dca4badcf 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -890,7 +890,7 @@ static gboolean test_debug_log = FALSE; static gboolean test_tap_log = TRUE; /* default to TAP as of GLib 2.62; see #1619; the non-TAP output mode is deprecated */ static gboolean test_nonfatal_assertions = FALSE; static DestroyEntry *test_destroy_queue = NULL; -static const char *test_argv0 = NULL; /* points into global argv */ +static const char *test_argv0 = NULL; /* (nullable), points into global argv */ static char *test_argv0_dirname = NULL; /* owned by GLib */ static const char *test_disted_files_dir; /* points into test_argv0_dirname or an environment variable */ static const char *test_built_files_dir; /* points into test_argv0_dirname or an environment variable */ @@ -1138,7 +1138,7 @@ parse_args (gint *argc_p, gchar **argv = *argv_p; guint i, e; - test_argv0 = argv[0]; + test_argv0 = argv[0]; /* will be NULL iff argc == 0 */ test_initial_cwd = g_get_current_dir (); /* parse known args */ @@ -1382,8 +1382,8 @@ parse_args (gint *argc_p, test_paths = g_slist_reverse (test_paths); /* collapse argv */ - e = 1; - for (i = 1; i < argc; i++) + e = 0; + for (i = 0; i < argc; i++) if (argv[i]) { argv[e++] = argv[i]; @@ -1732,7 +1732,7 @@ void g_log_set_default_handler (gtest_default_log_handler, NULL); g_test_log (G_TEST_LOG_START_BINARY, g_get_prgname(), test_run_seedstr, 0, NULL); - test_argv0_dirname = g_path_get_dirname (test_argv0); + test_argv0_dirname = (test_argv0 != NULL) ? g_path_get_dirname (test_argv0) : g_strdup ("."); /* Make sure we get the real dirname that the test was run from */ if (g_str_has_suffix (test_argv0_dirname, "/.libs")) @@ -3828,6 +3828,9 @@ g_test_trap_subprocess (const char *test_path, test_trap_clear (); test_trap_last_subprocess = g_strdup (test_path); + if (test_argv0 == NULL) + g_error ("g_test_trap_subprocess() requires argv0 to be passed to g_test_init()"); + argv = g_ptr_array_new (); g_ptr_array_add (argv, (char *) test_argv0); g_ptr_array_add (argv, "-q"); diff --git a/glib/tests/testing-helper.c b/glib/tests/testing-helper.c index 7b61e8337..7731538a0 100644 --- a/glib/tests/testing-helper.c +++ b/glib/tests/testing-helper.c @@ -102,6 +102,24 @@ main (int argc, argc -= 1; argv[argc] = NULL; + if (g_strcmp0 (argv1, "init-null-argv0") == 0) + { + int test_argc = 0; + char *test_argva[1] = { NULL }; + char **test_argv = test_argva; + + /* Test that `g_test_init()` can handle being called with an empty argv + * and argc == 0. While this isn’t recommended, it is possible for another + * process to use execve() to call a gtest process this way, so we’d + * better handle it gracefully. + * + * This test can’t be run after `g_test_init()` has been called normally, + * as it isn’t allowed to be called more than once in a process. */ + g_test_init (&test_argc, &test_argv, NULL); + + return 0; + } + g_test_init (&argc, &argv, NULL); g_test_set_nonfatal_assertions (); diff --git a/glib/tests/testing.c b/glib/tests/testing.c index c1fcd8c67..accd5dbfe 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -1585,6 +1585,40 @@ test_tap_summary (void) g_ptr_array_unref (argv); } +static void +test_init_no_argv0 (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + + g_test_summary ("Test that g_test_init() can be called safely with argc == 0."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "init-null-argv0"); + g_ptr_array_add (argv, NULL); + + /* This has to be spawned manually and can’t be run with g_test_subprocess() + * because the test helper can’t be run after `g_test_init()` has been called + * in the process. */ + g_spawn_sync (NULL, (char **) argv->pdata, NULL, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + g_assert_nonnull (strstr (output, "# random seed:")); + g_free (output); + g_ptr_array_unref (argv); +} + int main (int argc, char *argv[]) @@ -1682,6 +1716,8 @@ main (int argc, g_test_add_func ("/tap", test_tap); g_test_add_func ("/tap/summary", test_tap_summary); + g_test_add_func ("/init/no_argv0", test_init_no_argv0); + ret = g_test_run (); /* We can't test for https://gitlab.gnome.org/GNOME/glib/-/issues/2563