Skip to content

Commit 5140042

Browse files
kbleespatthoyts
authored andcommitted
Win32: reduce environment array reallocations
Move environment array reallocation from do_putenv to the respective callers. Keep track of the environment size in a global variable. Use ALLOC_GROW in mingw_putenv to reduce reallocations. Allocate a sufficiently sized environment array in make_environment_block to prevent reallocations. Signed-off-by: Karsten Blees <[email protected]>
1 parent f761051 commit 5140042

File tree

1 file changed

+34
-26
lines changed

1 file changed

+34
-26
lines changed

compat/mingw.c

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -758,33 +758,40 @@ static int lookupenv(char **env, const char *name, size_t nmln)
758758

759759
/*
760760
* If name contains '=', then sets the variable, otherwise it unsets it
761+
* Size includes the terminating NULL. Env must have room for size + 1 entries
762+
* (in case of insert). Returns the new size. Optionally frees removed entries.
761763
*/
762-
static char **do_putenv(char **env, const char *name, int free_old)
764+
static int do_putenv(char **env, const char *name, int size, int free_old)
763765
{
764766
char *eq = strchrnul(name, '=');
765767
int i = lookupenv(env, name, eq-name);
766768

767769
if (i < 0) {
768770
if (*eq) {
769-
for (i = 0; env[i]; i++)
770-
;
771-
env = xrealloc(env, (i+2)*sizeof(*env));
772-
env[i] = (char*) name;
773-
env[i+1] = NULL;
771+
env[size - 1] = (char*) name;
772+
env[size] = NULL;
773+
size++;
774774
}
775775
}
776776
else {
777777
if (free_old)
778778
free(env[i]);
779779
if (*eq)
780780
env[i] = (char*) name;
781-
else
781+
else {
782782
for (; env[i]; i++)
783783
env[i] = env[i+1];
784+
size--;
785+
}
784786
}
785-
return env;
787+
return size;
786788
}
787789

790+
/* used number of elements of environ array, including terminating NULL */
791+
static int environ_size = 0;
792+
/* allocated size of environ array, in bytes */
793+
static int environ_alloc = 0;
794+
788795
#undef getenv
789796
char *mingw_getenv(const char *name)
790797
{
@@ -804,7 +811,8 @@ char *mingw_getenv(const char *name)
804811

805812
int mingw_putenv(const char *namevalue)
806813
{
807-
environ = do_putenv(environ, namevalue, 1);
814+
ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
815+
environ_size = do_putenv(environ, namevalue, environ_size, 1);
808816
return 0;
809817
}
810818

@@ -1003,31 +1011,28 @@ static char *path_lookup(const char *cmd, char **path, int exe_only)
10031011
static wchar_t *make_environment_block(char **deltaenv)
10041012
{
10051013
wchar_t *wenvblk = NULL;
1006-
int count = 0;
1007-
char **e, **tmpenv;
1008-
int size = 0, wenvsz = 0, wenvpos = 0;
1014+
char **tmpenv;
1015+
int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
10091016

1010-
while (environ[count])
1011-
count++;
1017+
while (deltaenv && deltaenv[i])
1018+
i++;
10121019

1013-
/* copy the environment */
1014-
tmpenv = xmalloc(sizeof(*tmpenv) * (count + 1));
1015-
memcpy(tmpenv, environ, sizeof(*tmpenv) * (count + 1));
1020+
/* copy the environment, leaving space for changes */
1021+
tmpenv = xmalloc((size + i) * sizeof(char*));
1022+
memcpy(tmpenv, environ, size * sizeof(char*));
10161023

10171024
/* merge supplied environment changes into the temporary environment */
1018-
for (e = deltaenv; e && *e; e++)
1019-
tmpenv = do_putenv(tmpenv, *e, 0);
1025+
for (i = 0; deltaenv && deltaenv[i]; i++)
1026+
size = do_putenv(tmpenv, deltaenv[i], size, 0);
10201027

10211028
/* environment must be sorted */
1022-
for (count = 0; tmpenv[count]; )
1023-
count++;
1024-
qsort(tmpenv, count, sizeof(*tmpenv), compareenv);
1029+
qsort(tmpenv, size - 1, sizeof(char*), compareenv);
10251030

10261031
/* create environment block from temporary environment */
1027-
for (e = tmpenv; *e; e++) {
1028-
size = 2 * strlen(*e) + 2; /* +2 for final \0 */
1032+
for (i = 0; tmpenv[i]; i++) {
1033+
size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
10291034
ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
1030-
wenvpos += xutftowcs(&wenvblk[wenvpos], *e, size) + 1;
1035+
wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
10311036
}
10321037
/* add final \0 terminator */
10331038
wenvblk[wenvpos] = 0;
@@ -2060,7 +2065,9 @@ void mingw_startup()
20602065
maxlen = max(maxlen, wcslen(wenv[i]));
20612066

20622067
/* nedmalloc can't free CRT memory, allocate resizable environment list */
2063-
environ = xcalloc(i + 1, sizeof(char*));
2068+
environ = NULL;
2069+
environ_size = i + 1;
2070+
ALLOC_GROW(environ, environ_size * sizeof(char*), environ_alloc);
20642071

20652072
/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
20662073
maxlen = 3 * maxlen + 1;
@@ -2077,6 +2084,7 @@ void mingw_startup()
20772084
len = xwcstoutf(buffer, wenv[i], maxlen);
20782085
environ[i] = xmemdupz(buffer, len);
20792086
}
2087+
environ[i] = NULL;
20802088
free(buffer);
20812089

20822090
/* initialize critical section for waitpid pinfo_t list */

0 commit comments

Comments
 (0)