diff options
author | Luca Bacci <luca.bacci982@gmail.com> | 2023-03-09 12:38:04 +0100 |
---|---|---|
committer | Philip Withnall <pwithnall@endlessos.org> | 2023-04-14 17:15:28 +0100 |
commit | 5d1046d3b2c7756095f3ef61545add6f309fdcd9 (patch) | |
tree | 421e9b06ce85cbe13baec38e8ced7b4a5e3ecffa | |
parent | 911d091866333508c4a658ef100f2dbb156d9ead (diff) | |
download | glib-5d1046d3b2c7756095f3ef61545add6f309fdcd9.tar.gz |
Add test for UCRT issue workaround
-rw-r--r-- | glib/tests/spawn-test.c | 151 |
1 files changed, 150 insertions, 1 deletions
diff --git a/glib/tests/spawn-test.c b/glib/tests/spawn-test.c index b1b2eac0f..fdc35e86f 100644 --- a/glib/tests/spawn-test.c +++ b/glib/tests/spawn-test.c @@ -59,7 +59,136 @@ get_system_directory (void) return path; } -#endif + +static wchar_t * +g_wcsdup (const wchar_t *wcs_string) +{ + size_t length = wcslen (wcs_string); + + return g_memdup2 (wcs_string, (length + 1) * sizeof (wchar_t)); +} + +static wchar_t * +g_wcsndup (const wchar_t *wcs_string, + size_t length) +{ + wchar_t *result = NULL; + + g_assert_true (length < SIZE_MAX); + + result = g_new (wchar_t, length + 1); + memcpy (result, wcs_string, length * sizeof (wchar_t)); + result[length] = L'\0'; + + return result; +} + +/** + * parse_environment_string: + * + * @string: source environment string in the form <VARIABLE>=<VALUE> + * (e.g as returned by GetEnvironmentStrings) + * @name: (out) (optional) (utf-16) name of the variable + * @value: (out) (optional) (utf-16) value of the variable + * + * Parse environment string in the form <VARIABLE>=<VALUE>, for example + * the strings in the environment block returned by GetEnvironmentStrings. + * + * Returns: %TRUE on success + */ +static gboolean +parse_environment_string (const wchar_t *string, + wchar_t **name, + wchar_t **value) +{ + const wchar_t *equal_sign; + + g_assert_nonnull (string); + g_assert_true (name || value); + + /* On Windows environment variables may have an equal-sign + * character as part of their name, but only as the first + * character */ + equal_sign = wcschr (string[0] == L'=' ? (string + 1) : string, L'='); + + if (name) + *name = equal_sign ? g_wcsndup (string, equal_sign - string) : NULL; + + if (value) + *value = equal_sign ? g_wcsdup (equal_sign + 1) : NULL; + + return (equal_sign != NULL); +} + +/** + * find_cmd_shell_environment_variables: + * + * Finds all the environment variables related to cmd.exe, which are + * usually (but not always) present in a process environment block. + * Those environment variables are named "=X:", where X is a drive / + * volume letter and are used by cmd.exe to track per-drive current + * directories. + * + * See "What are these strange =C: environment variables?" + * https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133 + * + * This is used to test a work around for an UCRT issue + * https://developercommunity.visualstudio.com/t/UCRT-Crash-in-_wspawne-functions/10262748 + */ +static GList * +find_cmd_shell_environment_variables (void) +{ + wchar_t *block = NULL; + wchar_t *iter = NULL; + GList *variables = NULL; + size_t len = 0; + + block = GetEnvironmentStringsW (); + if (!block) + { + DWORD code = GetLastError (); + g_error ("%s failed with error code %u", + "GetEnvironmentStrings", (unsigned int) code); + } + + iter = block; + + while ((len = wcslen (iter))) + { + if (iter[0] == L'=') + { + wchar_t *variable = NULL; + + g_assert_true (parse_environment_string (iter, &variable, NULL)); + g_assert_nonnull (variable); + + variables = g_list_prepend (variables, variable); + } + + iter += len + 1; + } + + FreeEnvironmentStringsW (block); + + return variables; +} + +static void +remove_environment_variables (GList *list) +{ + for (GList *l = list; l; l = l->next) + { + const wchar_t *variable = (const wchar_t*) l->data; + + if (!SetEnvironmentVariableW (variable, NULL)) + { + DWORD code = GetLastError (); + g_error ("%s failed with error code %u", + "SetEnvironmentVariable", (unsigned int) code); + } + } +} +#endif /* G_OS_WIN32 */ static void test_spawn_basics (void) @@ -73,9 +202,11 @@ test_spawn_basics (void) char buf[100]; int pipedown[2], pipeup[2]; gchar **argv = NULL; + gchar **envp = g_get_environ (); gchar *system_directory; gchar spawn_binary[1000] = {0}; gchar full_cmdline[1000] = {0}; + GList *cmd_shell_env_vars = NULL; const LCID old_lcid = GetThreadUILanguage (); const unsigned int initial_cp = GetConsoleOutputCP (); @@ -253,11 +384,29 @@ test_spawn_basics (void) buf[n] = '\0'; g_assert_cmpstr (buf, ==, "See ya"); + + /* Test workaround for: + * + * https://developercommunity.visualstudio.com/t/UCRT-Crash-in-_wspawne-functions/10262748 + */ + cmd_shell_env_vars = find_cmd_shell_environment_variables (); + remove_environment_variables (cmd_shell_env_vars); + + g_snprintf (full_cmdline, sizeof (full_cmdline), + "'%s\\sort.exe' non-existing-file.txt", system_directory); + g_assert_true (g_shell_parse_argv (full_cmdline, NULL, &argv, NULL)); + g_assert_nonnull (argv); + g_spawn_sync (NULL, argv, envp, G_SPAWN_DEFAULT, + NULL, NULL, NULL, NULL, NULL, NULL); + g_free (argv); + argv = NULL; #endif #ifdef G_OS_WIN32 SetThreadUILanguage (old_lcid); SetConsoleOutputCP (initial_cp); /* 437 means en-US codepage */ + g_list_free_full (cmd_shell_env_vars, g_free); + g_strfreev (envp); g_free (system_directory); #endif } |