mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-04-16 04:28:05 +02:00
gtestutils: Handle empty argv array passed to g_test_init()
This can happen if a caller (ab)uses `execve()` to execute a gtest process with an empty `argv` array. `g_test_init()` has to gracefully handle such a situation. Fix a few problem areas in the code, and add a simple test which checks that `g_test_init()` doesn’t crash when called with an empty `argv`. Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
This commit is contained in:
parent
44f4d55150
commit
a6311f81ee
@ -668,8 +668,8 @@ parse_args (gint *argc_p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* collapse argv */
|
/* collapse argv */
|
||||||
e = 1;
|
e = 0;
|
||||||
for (i = 1; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
if (argv[i])
|
if (argv[i])
|
||||||
{
|
{
|
||||||
argv[e++] = argv[i];
|
argv[e++] = argv[i];
|
||||||
|
@ -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_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 gboolean test_nonfatal_assertions = FALSE;
|
||||||
static DestroyEntry *test_destroy_queue = NULL;
|
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 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_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 */
|
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;
|
gchar **argv = *argv_p;
|
||||||
guint i, e;
|
guint i, e;
|
||||||
|
|
||||||
test_argv0 = argv[0];
|
test_argv0 = argv[0]; /* will be NULL iff argc == 0 */
|
||||||
test_initial_cwd = g_get_current_dir ();
|
test_initial_cwd = g_get_current_dir ();
|
||||||
|
|
||||||
/* parse known args */
|
/* parse known args */
|
||||||
@ -1382,8 +1382,8 @@ parse_args (gint *argc_p,
|
|||||||
test_paths = g_slist_reverse (test_paths);
|
test_paths = g_slist_reverse (test_paths);
|
||||||
|
|
||||||
/* collapse argv */
|
/* collapse argv */
|
||||||
e = 1;
|
e = 0;
|
||||||
for (i = 1; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
if (argv[i])
|
if (argv[i])
|
||||||
{
|
{
|
||||||
argv[e++] = argv[i];
|
argv[e++] = argv[i];
|
||||||
@ -1732,7 +1732,7 @@ void
|
|||||||
g_log_set_default_handler (gtest_default_log_handler, NULL);
|
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);
|
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 */
|
/* Make sure we get the real dirname that the test was run from */
|
||||||
if (g_str_has_suffix (test_argv0_dirname, "/.libs"))
|
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_clear ();
|
||||||
test_trap_last_subprocess = g_strdup (test_path);
|
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 ();
|
argv = g_ptr_array_new ();
|
||||||
g_ptr_array_add (argv, (char *) test_argv0);
|
g_ptr_array_add (argv, (char *) test_argv0);
|
||||||
g_ptr_array_add (argv, "-q");
|
g_ptr_array_add (argv, "-q");
|
||||||
|
@ -102,6 +102,24 @@ main (int argc,
|
|||||||
argc -= 1;
|
argc -= 1;
|
||||||
argv[argc] = NULL;
|
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_init (&argc, &argv, NULL);
|
||||||
g_test_set_nonfatal_assertions ();
|
g_test_set_nonfatal_assertions ();
|
||||||
|
|
||||||
|
@ -1585,6 +1585,40 @@ test_tap_summary (void)
|
|||||||
g_ptr_array_unref (argv);
|
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
|
int
|
||||||
main (int argc,
|
main (int argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
@ -1682,6 +1716,8 @@ main (int argc,
|
|||||||
g_test_add_func ("/tap", test_tap);
|
g_test_add_func ("/tap", test_tap);
|
||||||
g_test_add_func ("/tap/summary", test_tap_summary);
|
g_test_add_func ("/tap/summary", test_tap_summary);
|
||||||
|
|
||||||
|
g_test_add_func ("/init/no_argv0", test_init_no_argv0);
|
||||||
|
|
||||||
ret = g_test_run ();
|
ret = g_test_run ();
|
||||||
|
|
||||||
/* We can't test for https://gitlab.gnome.org/GNOME/glib/-/issues/2563
|
/* We can't test for https://gitlab.gnome.org/GNOME/glib/-/issues/2563
|
||||||
|
Loading…
x
Reference in New Issue
Block a user