summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Bacci <luca.bacci982@gmail.com>2023-03-09 12:38:04 +0100
committerPhilip Withnall <pwithnall@endlessos.org>2023-04-14 17:15:28 +0100
commit5d1046d3b2c7756095f3ef61545add6f309fdcd9 (patch)
tree421e9b06ce85cbe13baec38e8ced7b4a5e3ecffa
parent911d091866333508c4a658ef100f2dbb156d9ead (diff)
downloadglib-5d1046d3b2c7756095f3ef61545add6f309fdcd9.tar.gz
Add test for UCRT issue workaround
-rw-r--r--glib/tests/spawn-test.c151
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
}