From 9eb4fe3c00a84190431f0e71143eafc48235d643 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sun, 31 Jan 2021 14:01:06 +0000 Subject: [PATCH] Expand test coverage for G_SPAWN_SEARCH_PATH Signed-off-by: Simon McVittie --- glib/tests/spawn-path-search-helper.c | 15 ++ glib/tests/spawn-path-search.c | 200 ++++++++++++++++++++++++++ 2 files changed, 215 insertions(+) diff --git a/glib/tests/spawn-path-search-helper.c b/glib/tests/spawn-path-search-helper.c index b417c7896..378c203c7 100644 --- a/glib/tests/spawn-path-search-helper.c +++ b/glib/tests/spawn-path-search-helper.c @@ -55,6 +55,7 @@ main (int argc, gboolean search_path = FALSE; gboolean search_path_from_envp = FALSE; gboolean slow_path = FALSE; + gboolean unset_path_in_envp = FALSE; gchar *chdir_child = NULL; gchar *set_path_in_envp = NULL; gchar **envp = NULL; @@ -72,6 +73,9 @@ main (int argc, { "set-path-in-envp", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME, &set_path_in_envp, "Set PATH in specified environment to this value", "PATH", }, + { "unset-path-in-envp", '\0', + G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &unset_path_in_envp, + "Unset PATH in specified environment", NULL }, { "slow-path", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &slow_path, "Use a child-setup function to avoid the posix_spawn fast path", NULL }, @@ -102,9 +106,20 @@ main (int argc, envp = g_get_environ (); + if (set_path_in_envp != NULL && unset_path_in_envp) + { + g_set_error (&error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + "Cannot both set PATH and unset it"); + ret = 2; + goto out; + } + if (set_path_in_envp != NULL) envp = g_environ_setenv (envp, "PATH", set_path_in_envp, TRUE); + if (unset_path_in_envp) + envp = g_environ_unsetenv (envp, "PATH"); + if (search_path) spawn_flags |= G_SPAWN_SEARCH_PATH; diff --git a/glib/tests/spawn-path-search.c b/glib/tests/spawn-path-search.c index 9fbfd478e..f4278f3e0 100644 --- a/glib/tests/spawn-path-search.c +++ b/glib/tests/spawn-path-search.c @@ -239,6 +239,200 @@ test_search_path_ambiguous (void) g_ptr_array_unref (argv); } +static void +test_search_path_fallback_in_environ (void) +{ + GPtrArray *argv = g_ptr_array_new_with_free_func (g_free); + gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL); + gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL); + gchar **envp = g_get_environ (); + gchar *out = NULL; + gchar *err = NULL; + GError *error = NULL; + int wait_status = -1; + + g_test_summary ("With G_SPAWN_SEARCH_PATH but no PATH, a fallback is used."); + /* We can't make a meaningful assertion about what the fallback *is*, + * but we can assert that it *includes* the current working directory. */ + + if (g_file_test ("/usr/bin/spawn-test-helper", G_FILE_TEST_IS_EXECUTABLE) || + g_file_test ("/bin/spawn-test-helper", G_FILE_TEST_IS_EXECUTABLE)) + { + g_test_skip ("Not testing fallback with unknown spawn-test-helper " + "executable in /usr/bin:/bin"); + return; + } + + envp = g_environ_unsetenv (envp, "PATH"); + + g_ptr_array_add (argv, + g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL)); + g_ptr_array_add (argv, g_strdup ("--search-path")); + g_ptr_array_add (argv, g_strdup ("--set-path-in-envp")); + g_ptr_array_add (argv, g_strdup (subdir)); + g_ptr_array_add (argv, g_strdup ("--")); + g_ptr_array_add (argv, g_strdup ("spawn-test-helper")); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (here, + (char **) argv->pdata, + envp, + G_SPAWN_DEFAULT, + NULL, /* child setup */ + NULL, /* user data */ + &out, + &err, + &wait_status, + &error); + g_assert_no_error (error); + + g_test_message ("%s", out); + g_test_message ("%s", err); + g_assert_nonnull (strstr (err, "this is spawn-test-helper from glib/tests")); + +#ifdef G_OS_UNIX + g_assert_true (WIFEXITED (wait_status)); + g_assert_cmpint (WEXITSTATUS (wait_status), ==, 0); +#endif + + g_strfreev (envp); + g_free (here); + g_free (subdir); + g_free (out); + g_free (err); + g_ptr_array_unref (argv); +} + +static void +test_search_path_fallback_in_envp (void) +{ + GPtrArray *argv = g_ptr_array_new_with_free_func (g_free); + gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL); + gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL); + gchar **envp = g_get_environ (); + gchar *out = NULL; + gchar *err = NULL; + GError *error = NULL; + int wait_status = -1; + + g_test_summary ("With G_SPAWN_SEARCH_PATH_FROM_ENVP but no PATH, a fallback is used."); + /* We can't make a meaningful assertion about what the fallback *is*, + * but we can assert that it *includes* the current working directory. */ + + if (g_file_test ("/usr/bin/spawn-test-helper", G_FILE_TEST_IS_EXECUTABLE) || + g_file_test ("/bin/spawn-test-helper", G_FILE_TEST_IS_EXECUTABLE)) + { + g_test_skip ("Not testing fallback with unknown spawn-test-helper " + "executable in /usr/bin:/bin"); + return; + } + + envp = g_environ_setenv (envp, "PATH", subdir, TRUE); + + g_ptr_array_add (argv, + g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL)); + g_ptr_array_add (argv, g_strdup ("--search-path-from-envp")); + g_ptr_array_add (argv, g_strdup ("--unset-path-in-envp")); + g_ptr_array_add (argv, g_strdup ("--")); + g_ptr_array_add (argv, g_strdup ("spawn-test-helper")); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (here, + (char **) argv->pdata, + envp, + G_SPAWN_DEFAULT, + NULL, /* child setup */ + NULL, /* user data */ + &out, + &err, + &wait_status, + &error); + g_assert_no_error (error); + + g_test_message ("%s", out); + g_test_message ("%s", err); + g_assert_nonnull (strstr (err, "this is spawn-test-helper from glib/tests")); + +#ifdef G_OS_UNIX + g_assert_true (WIFEXITED (wait_status)); + g_assert_cmpint (WEXITSTATUS (wait_status), ==, 0); +#endif + + g_strfreev (envp); + g_free (here); + g_free (subdir); + g_free (out); + g_free (err); + g_ptr_array_unref (argv); +} + +static void +test_search_path_heap_allocation (void) +{ + GPtrArray *argv = g_ptr_array_new_with_free_func (g_free); + /* Must be longer than the arbitrary 4000 byte limit for stack allocation + * in gspawn.c */ + char placeholder[4096]; + gchar *here = g_test_build_filename (G_TEST_BUILT, ".", NULL); + gchar *subdir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", NULL); + gchar *long_dir = NULL; + gchar *long_path = NULL; + gchar **envp = g_get_environ (); + gchar *out = NULL; + gchar *err = NULL; + GError *error = NULL; + int wait_status = -1; + gsize i; + + memset (placeholder, '_', sizeof (placeholder)); + /* Force search_path_buffer to be heap-allocated */ + long_dir = g_test_build_filename (G_TEST_BUILT, "path-test-subdir", placeholder, NULL); + long_path = g_strjoin (G_SEARCHPATH_SEPARATOR_S, subdir, long_dir, NULL); + envp = g_environ_setenv (envp, "PATH", long_path, TRUE); + + g_ptr_array_add (argv, + g_test_build_filename (G_TEST_BUILT, "spawn-path-search-helper", NULL)); + g_ptr_array_add (argv, g_strdup ("--search-path")); + g_ptr_array_add (argv, g_strdup ("--")); + g_ptr_array_add (argv, g_strdup ("spawn-test-helper")); + + /* Add enough arguments to make argv longer than the arbitrary 4000 byte + * limit for stack allocation in gspawn.c. + * This assumes sizeof (char *) >= 4. */ + for (i = 0; i < 1001; i++) + g_ptr_array_add (argv, g_strdup ("_")); + + g_ptr_array_add (argv, NULL); + + g_spawn_sync (here, + (char **) argv->pdata, + envp, + G_SPAWN_DEFAULT, + NULL, /* child setup */ + NULL, /* user data */ + &out, + &err, + &wait_status, + &error); + g_assert_no_error (error); + + g_test_message ("%s", out); + g_test_message ("%s", err); + g_assert_nonnull (strstr (err, "this is spawn-test-helper from path-test-subdir")); + +#ifdef G_OS_UNIX + g_assert_true (WIFEXITED (wait_status)); + g_assert_cmpint (WEXITSTATUS (wait_status), ==, 5); +#endif + + g_strfreev (envp); + g_free (here); + g_free (subdir); + g_free (out); + g_free (err); + g_ptr_array_unref (argv); +} + int main (int argc, char **argv) @@ -249,6 +443,12 @@ main (int argc, g_test_add_func ("/spawn/search-path", test_search_path); g_test_add_func ("/spawn/search-path-from-envp", test_search_path_from_envp); g_test_add_func ("/spawn/search-path-ambiguous", test_search_path_ambiguous); + g_test_add_func ("/spawn/search-path-heap-allocation", + test_search_path_heap_allocation); + g_test_add_func ("/spawn/search-path-fallback-in-environ", + test_search_path_fallback_in_environ); + g_test_add_func ("/spawn/search-path-fallback-in-envp", + test_search_path_fallback_in_envp); return g_test_run (); }