gsubprocess: Copy parent process’ environ when clearing subprocess’

Previously, this was done at the time of spawning the subprocess, which
meant the g_subprocess_launcher_*_environ() functions could not be used
to modify the parent process’ environment.

Change the code to copy the parent process’ environment when
g_subprocess_launcher_set_environ(NULL) is called. Document the change
and add a unit test.

https://bugzilla.gnome.org/show_bug.cgi?id=778422
This commit is contained in:
Philip Withnall 2017-03-30 11:02:14 +01:00
parent c7d325733c
commit e1e73dafa6
2 changed files with 55 additions and 2 deletions

View File

@ -240,8 +240,12 @@ g_subprocess_launcher_new (GSubprocessFlags flags)
* As an alternative, you can use g_subprocess_launcher_setenv(), * As an alternative, you can use g_subprocess_launcher_setenv(),
* g_subprocess_launcher_unsetenv(), etc. * g_subprocess_launcher_unsetenv(), etc.
* *
* Pass %NULL to inherit the parent process' environment. Pass an * Pass an empty array to set an empty environment. Pass %NULL to inherit the
* empty array to set an empty environment. * parent process environment. As of GLib 2.54, the parent process environment
* will be copied when g_subprocess_launcher_set_environ() is called.
* Previously, it was copied when the subprocess was executed. This means the
* copied environment may now be modified (using g_subprocess_launcher_setenv(),
* etc.) before launching the subprocess.
* *
* On UNIX, all strings in this array can be arbitrary byte strings. * On UNIX, all strings in this array can be arbitrary byte strings.
* On Windows, they should be in UTF-8. * On Windows, they should be in UTF-8.
@ -254,6 +258,9 @@ g_subprocess_launcher_set_environ (GSubprocessLauncher *self,
{ {
g_strfreev (self->envp); g_strfreev (self->envp);
self->envp = g_strdupv (env); self->envp = g_strdupv (env);
if (self->envp == NULL)
self->envp = g_get_environ ();
} }
/** /**

View File

@ -948,6 +948,51 @@ test_env (void)
g_object_unref (proc); g_object_unref (proc);
} }
/* Test that explicitly inheriting and modifying the parent process
* environment works. */
static void
test_env_inherit (void)
{
GError *local_error = NULL;
GError **error = &local_error;
GSubprocessLauncher *launcher;
GSubprocess *proc;
GPtrArray *args;
GInputStream *stdout;
gchar *result;
gchar **split;
g_setenv ("TEST_ENV_INHERIT1", "1", TRUE);
g_setenv ("TEST_ENV_INHERIT2", "2", TRUE);
args = get_test_subprocess_args ("env", NULL);
launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
g_subprocess_launcher_set_flags (launcher, G_SUBPROCESS_FLAGS_STDOUT_PIPE);
g_subprocess_launcher_set_environ (launcher, NULL);
g_subprocess_launcher_setenv (launcher, "TWO", "2", TRUE);
g_subprocess_launcher_unsetenv (launcher, "TEST_ENV_INHERIT1");
g_assert_null (g_subprocess_launcher_getenv (launcher, "TEST_ENV_INHERIT1"));
g_assert_cmpstr (g_subprocess_launcher_getenv (launcher, "TEST_ENV_INHERIT2"), ==, "2");
g_assert_cmpstr (g_subprocess_launcher_getenv (launcher, "TWO"), ==, "2");
proc = g_subprocess_launcher_spawn (launcher, error, args->pdata[0], "env", NULL);
g_ptr_array_free (args, TRUE);
g_assert_no_error (local_error);
stdout = g_subprocess_get_stdout_pipe (proc);
result = splice_to_string (stdout, error);
split = g_strsplit (result, "\n", -1);
g_assert_null (g_environ_getenv (split, "TEST_ENV_INHERIT1"));
g_assert_cmpstr (g_environ_getenv (split, "TEST_ENV_INHERIT2"), ==, "2");
g_assert_cmpstr (g_environ_getenv (split, "TWO"), ==, "2");
g_strfreev (split);
g_free (result);
g_object_unref (proc);
}
static void static void
test_cwd (void) test_cwd (void)
{ {
@ -1265,6 +1310,7 @@ main (int argc, char **argv)
g_test_add_func ("/gsubprocess/communicate-nothing", test_communicate_nothing); g_test_add_func ("/gsubprocess/communicate-nothing", test_communicate_nothing);
g_test_add_func ("/gsubprocess/terminate", test_terminate); g_test_add_func ("/gsubprocess/terminate", test_terminate);
g_test_add_func ("/gsubprocess/env", test_env); g_test_add_func ("/gsubprocess/env", test_env);
g_test_add_func ("/gsubprocess/env/inherit", test_env_inherit);
g_test_add_func ("/gsubprocess/cwd", test_cwd); g_test_add_func ("/gsubprocess/cwd", test_cwd);
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
g_test_add_func ("/gsubprocess/stdout-file", test_stdout_file); g_test_add_func ("/gsubprocess/stdout-file", test_stdout_file);