Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit e6e3f76

Browse files
kbleeskasal
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 c6f9aae commit e6e3f76

File tree

3 files changed

+28
-64
lines changed

3 files changed

+28
-64
lines changed

compat/mingw.c

Lines changed: 24 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ static int lookupenv(char **env, const char *name, size_t nmln)
735735
/*
736736
* If name contains '=', then sets the variable, otherwise it unsets it
737737
*/
738-
static char **do_putenv(char **env, const char *name)
738+
static char **do_putenv(char **env, const char *name, int free_old)
739739
{
740740
char *eq = strchrnul(name, '=');
741741
int i = lookupenv(env, name, eq-name);
@@ -750,7 +750,8 @@ static char **do_putenv(char **env, const char *name)
750750
}
751751
}
752752
else {
753-
free(env[i]);
753+
if (free_old)
754+
free(env[i]);
754755
if (*eq)
755756
env[i] = (char*) name;
756757
else
@@ -779,7 +780,7 @@ char *mingw_getenv(const char *name)
779780

780781
int mingw_putenv(const char *namevalue)
781782
{
782-
environ = do_putenv(environ, namevalue);
783+
environ = do_putenv(environ, namevalue, 1);
783784
return 0;
784785
}
785786

@@ -966,21 +967,30 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
966967
}
967968

968969
/*
969-
* Create environment block suitable for CreateProcess.
970+
* Create environment block suitable for CreateProcess. Merges current
971+
* process environment and the supplied environment changes.
970972
*/
971-
static wchar_t *make_environment_block(char **env)
973+
static wchar_t *make_environment_block(char **deltaenv)
972974
{
973975
wchar_t *wenvblk = NULL;
974976
int count = 0;
975977
char **e, **tmpenv;
976978
int size = 0, wenvsz = 0, wenvpos = 0;
977979

978-
for (e = env; *e; e++)
980+
while (environ[count])
979981
count++;
980982

981-
/* environment must be sorted */
983+
/* copy the environment */
982984
tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
983-
memcpy(tmpenv, env, sizeof(*tmpenv) * (count + 1));
985+
memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
986+
987+
/* merge supplied environment changes into the temporary environment */
988+
for (e = deltaenv; e && *e; e++)
989+
tmpenv = do_putenv(tmpenv, *e, 0);
990+
991+
/* environment must be sorted */
992+
for (count = 0; tmpenv[count]; )
993+
count++;
984994
qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
985995

986996
/* create environment block from temporary environment */
@@ -1003,7 +1013,7 @@ struct pinfo_t {
10031013
static struct pinfo_t *pinfo = NULL;
10041014
CRITICAL_SECTION pinfo_cs;
10051015

1006-
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
1016+
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
10071017
const char *dir,
10081018
int prepend_cmd, int fhin, int fhout, int fherr)
10091019
{
@@ -1071,8 +1081,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
10711081
xutftowcs(wargs, args.buf, 2 * args.len + 1);
10721082
strbuf_release(&args);
10731083

1074-
if (env)
1075-
wenvblk = make_environment_block(env);
1084+
wenvblk = make_environment_block(deltaenv);
10761085

10771086
memset(&pi, 0, sizeof(pi));
10781087
ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
@@ -1110,10 +1119,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
11101119

11111120
static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
11121121
{
1113-
return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
1122+
return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
11141123
}
11151124

1116-
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
1125+
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
11171126
const char *dir,
11181127
int fhin, int fhout, int fherr)
11191128
{
@@ -1137,14 +1146,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
11371146
pid = -1;
11381147
}
11391148
else {
1140-
pid = mingw_spawnve_fd(iprog, argv, env, dir, 1,
1149+
pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
11411150
fhin, fhout, fherr);
11421151
free(iprog);
11431152
}
11441153
argv[0] = argv0;
11451154
}
11461155
else
1147-
pid = mingw_spawnve_fd(prog, argv, env, dir, 0,
1156+
pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
11481157
fhin, fhout, fherr);
11491158
free(prog);
11501159
}
@@ -1241,41 +1250,6 @@ int mingw_kill(pid_t pid, int sig)
12411250
return -1;
12421251
}
12431252

1244-
static char **copy_environ(void)
1245-
{
1246-
char **env;
1247-
int i = 0;
1248-
while (environ[i])
1249-
i++;
1250-
env = xmalloc((i+1)*sizeof(*env));
1251-
for (i = 0; environ[i]; i++)
1252-
env[i] = xstrdup(environ[i]);
1253-
env[i] = NULL;
1254-
return env;
1255-
}
1256-
1257-
void free_environ(char **env)
1258-
{
1259-
int i;
1260-
for (i = 0; env[i]; i++)
1261-
free(env[i]);
1262-
free(env);
1263-
}
1264-
1265-
/*
1266-
* Copies global environ and adjusts variables as specified by vars.
1267-
*/
1268-
char **make_augmented_environ(const char *const *vars)
1269-
{
1270-
char **env = copy_environ();
1271-
1272-
while (*vars) {
1273-
const char *v = *vars++;
1274-
env = do_putenv(env, strchr(v, '=') ? xstrdup(v) : v);
1275-
}
1276-
return env;
1277-
}
1278-
12791253
/*
12801254
* Note, this isn't a complete replacement for getaddrinfo. It assumes
12811255
* that service contains a numerical port, or that it is null. It

compat/mingw.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -357,12 +357,8 @@ static inline char *mingw_find_last_dir_sep(const char *path)
357357
void mingw_open_html(const char *path);
358358
#define open_html mingw_open_html
359359

360-
/*
361-
* helpers
362-
*/
363-
364-
char **make_augmented_environ(const char *const *vars);
365-
void free_environ(char **env);
360+
void mingw_mark_as_git_dir(const char *dir);
361+
#define mark_as_git_dir mingw_mark_as_git_dir
366362

367363
/**
368364
* 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
@@ -450,7 +450,6 @@ int start_command(struct child_process *cmd)
450450
{
451451
int fhin = 0, fhout = 1, fherr = 2;
452452
const char **sargv = cmd->argv;
453-
char **env = environ;
454453

455454
if (cmd->no_stdin)
456455
fhin = open("/dev/null", O_RDWR);
@@ -475,24 +474,19 @@ int start_command(struct child_process *cmd)
475474
else if (cmd->out > 1)
476475
fhout = dup(cmd->out);
477476

478-
if (cmd->env)
479-
env = make_augmented_environ(cmd->env);
480-
481477
if (cmd->git_cmd)
482478
cmd->argv = prepare_git_cmd(cmd->argv);
483479
else if (cmd->use_shell)
484480
cmd->argv = prepare_shell_cmd(cmd->argv);
485481

486-
cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env, cmd->dir,
487-
fhin, fhout, fherr);
482+
cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, (char**) cmd->env,
483+
cmd->dir, fhin, fhout, fherr);
488484
failed_errno = errno;
489485
if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
490486
error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
491487
if (cmd->clean_on_exit && cmd->pid >= 0)
492488
mark_child_for_cleanup(cmd->pid);
493489

494-
if (cmd->env)
495-
free_environ(env);
496490
if (cmd->git_cmd)
497491
free(cmd->argv);
498492

0 commit comments

Comments
 (0)