Skip to content

Commit f761051

Browse files
kbleespatthoyts
authored andcommitted
Win32: don't copy the environment twice when spawning child processes
When spawning child processes via start_command(), the environment and all environment entries are copied twice. First by make_augmented_environ / copy_environ to merge with child_process.env. Then a second time by make_environment_block to create a sorted environment block string as required by CreateProcess. Move the merge logic to make_environment_block so that we only need to copy the environment once. This changes semantics of the env parameter: it now expects a delta (such as child_process.env) rather than a full environment. This is not a problem as the parameter is only used by start_command() (all other callers previously passed char **environ, and now pass NULL). The merge logic no longer xstrdup()s the environment strings, so do_putenv must not free them. Add a parameter to distinguish this from normal putenv. Remove the now unused make_augmented_environ / free_environ API. Signed-off-by: Karsten Blees <[email protected]>
1 parent 4fa72bc commit f761051

File tree

3 files changed

+26
-64
lines changed

3 files changed

+26
-64
lines changed

compat/mingw.c

Lines changed: 24 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
759759
/*
760760
* If name contains '=', then sets the variable, otherwise it unsets it
761761
*/
762-
static char **do_putenv(char **env, const char *name)
762+
static char **do_putenv(char **env, const char *name, int free_old)
763763
{
764764
char *eq = strchrnul(name, '=');
765765
int i = lookupenv(env, name, eq-name);
@@ -774,7 +774,8 @@ static char **do_putenv(char **env, const char *name)
774774
}
775775
}
776776
else {
777-
free(env[i]);
777+
if (free_old)
778+
free(env[i]);
778779
if (*eq)
779780
env[i] = (char*) name;
780781
else
@@ -803,7 +804,7 @@ char *mingw_getenv(const char *name)
803804

804805
int mingw_putenv(const char *namevalue)
805806
{
806-
environ = do_putenv(environ, namevalue);
807+
environ = do_putenv(environ, namevalue, 1);
807808
return 0;
808809
}
809810

@@ -996,21 +997,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
996997
}
997998

998999
/*
999-
* Create environment block suitable for CreateProcess.
1000+
* Create environment block suitable for CreateProcess. Merges current
1001+
* process environment and the supplied environment changes.
10001002
*/
1001-
static wchar_t *make_environment_block(char **env)
1003+
static wchar_t *make_environment_block(char **deltaenv)
10021004
{
10031005
wchar_t *wenvblk = NULL;
10041006
int count = 0;
10051007
char **e, **tmpenv;
10061008
int size = 0, wenvsz = 0, wenvpos = 0;
10071009

1008-
for (e = env; *e; e++)
1010+
while (environ[count])
10091011
count++;
10101012

1011-
/* environment must be sorted */
1013+
/* copy the environment */
10121014
tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
1013-
memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
1015+
memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
1016+
1017+
/* merge supplied environment changes into the temporary environment */
1018+
for (e = deltaenv; e && *e; e++)
1019+
tmpenv = do_putenv(tmpenv, *e, 0);
1020+
1021+
/* environment must be sorted */
1022+
for (count = 0; tmpenv[count]; )
1023+
count++;
10141024
qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
10151025

10161026
/* create environment block from temporary environment */
@@ -1033,7 +1043,7 @@ struct pinfo_t {
10331043
struct pinfo_t *pinfo = NULL;
10341044
CRITICAL_SECTION pinfo_cs;
10351045

1036-
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
1046+
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
10371047
const char *dir,
10381048
int prepend_cmd, int fhin, int fhout, int fherr)
10391049
{
@@ -1101,8 +1111,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
11011111
xutftowcs(wargs, args.buf, 2 * args.len + 1);
11021112
strbuf_release(&args);
11031113

1104-
if (env)
1105-
wenvblk = make_environment_block(env);
1114+
wenvblk = make_environment_block(deltaenv);
11061115

11071116
memset(&pi, 0, sizeof(pi));
11081117
ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1140,10 +1149,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
11401149

11411150
static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
11421151
{
1143-
return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
1152+
return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
11441153
}
11451154

1146-
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
1155+
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
11471156
const char *dir,
11481157
int fhin, int fhout, int fherr)
11491158
{
@@ -1167,14 +1176,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
11671176
pid = -1;
11681177
}
11691178
else {
1170-
pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
1179+
pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
11711180
fhin, fhout, fherr);
11721181
free(iprog);
11731182
}
11741183
argv[0] = argv0;
11751184
}
11761185
else
1177-
pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
1186+
pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
11781187
fhin, fhout, fherr);
11791188
free(prog);
11801189
}
@@ -1265,41 +1274,6 @@ int mingw_kill(pid_t pid, int sig)
12651274
return -1;
12661275
}
12671276

1268-
static char **copy_environ(void)
1269-
{
1270-
char **env;
1271-
int i = 0;
1272-
while (environ[i])
1273-
i++;
1274-
env = xmalloc((i+1)*sizeof(*env));
1275-
for (i = 0; environ[i]; i++)
1276-
env[i] = xstrdup(environ[i]);
1277-
env[i] = NULL;
1278-
return env;
1279-
}
1280-
1281-
void free_environ(char **env)
1282-
{
1283-
int i;
1284-
for (i = 0; env[i]; i++)
1285-
free(env[i]);
1286-
free(env);
1287-
}
1288-
1289-
/*
1290-
* Copies global environ and adjusts variables as specified by vars.
1291-
*/
1292-
char **make_augmented_environ(const char *const *vars)
1293-
{
1294-
char **env = copy_environ();
1295-
1296-
while (*vars) {
1297-
const char *v = *vars++;
1298-
env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
1299-
}
1300-
return env;
1301-
}
1302-
13031277
/*
13041278
* Note, this isn't a complete replacement for getaddrinfo. It assumes
13051279
* that service contains a numerical port, or that it is null. It

compat/mingw.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -335,12 +335,6 @@ void mingw_open_html(const char *path);
335335
void mingw_mark_as_git_dir(const char *dir);
336336
#define mark_as_git_dir mingw_mark_as_git_dir
337337

338-
/*
339-
* helpers
340-
*/
341-
342-
char **make_augmented_environ(const char *const *vars);
343-
void free_environ(char **env);
344338

345339
/**
346340
* Converts UTF-8 encoded string to UTF-16LE.

run-command.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,6 @@ int start_command(struct child_process *cmd)
454454
{
455455
int fhin = 0, fhout = 1, fherr = 2;
456456
const char **sargv = cmd->argv;
457-
char **env = environ;
458457

459458
if (cmd->no_stdin)
460459
fhin = open("/dev/null", O_RDWR);
@@ -479,25 +478,20 @@ int start_command(struct child_process *cmd)
479478
else if (cmd->out > 1)
480479
fhout = dup(cmd->out);
481480

482-
if (cmd->env)
483-
env = make_augmented_environ(cmd->env);
484-
485481
if (cmd->git_cmd) {
486482
cmd->argv = prepare_git_cmd(cmd->argv);
487483
} else if (cmd->use_shell) {
488484
cmd->argv = prepare_shell_cmd(cmd->argv);
489485
}
490486

491-
cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
492-
fhin, fhout, fherr);
487+
cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
488+
cmd->dir, fhin, fhout, fherr);
493489
failed_errno = errno;
494490
if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
495491
error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
496492
if (cmd->clean_on_exit && cmd->pid >= 0)
497493
mark_child_for_cleanup(cmd->pid);
498494

499-
if (cmd->env)
500-
free_environ(env);
501495
if (cmd->git_cmd)
502496
free(cmd->argv);
503497

0 commit comments

Comments
 (0)