Skip to content

Commit 3ee6eff

Browse files
committed
Merge pull request #38 from dscho/mingw-environment
Fix access violations when cloning/fetching via HTTPS
2 parents e9d0cf4 + 12e5c37 commit 3ee6eff

File tree

1 file changed

+58
-7
lines changed

1 file changed

+58
-7
lines changed

compat/mingw.c

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,10 @@ static int do_putenv(char **env, const char *name, int size, int free_old);
966966
static int environ_size = 0;
967967
/* allocated size of environ array, in bytes */
968968
static int environ_alloc = 0;
969+
/* used as a indicator when the environment has been changed outside mingw.c */
970+
static char **saved_environ;
971+
972+
static void maybe_reinitialize_environ(void);
969973

970974
/*
971975
* Create environment block suitable for CreateProcess. Merges current
@@ -975,21 +979,24 @@ static wchar_t *make_environment_block(char **deltaenv)
975979
{
976980
wchar_t *wenvblk = NULL;
977981
char **tmpenv;
978-
int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
982+
int i = 0, size, wenvsz = 0, wenvpos = 0;
983+
984+
maybe_reinitialize_environ();
985+
size = environ_size;
979986

980-
while (deltaenv && deltaenv[i])
987+
while (deltaenv && deltaenv[i] && *deltaenv[i])
981988
i++;
982989

983990
/* copy the environment, leaving space for changes */
984991
tmpenv = xmalloc((size + i) * sizeof(char*));
985992
memcpy(tmpenv, environ, size * sizeof(char*));
986993

987994
/* merge supplied environment changes into the temporary environment */
988-
for (i = 0; deltaenv && deltaenv[i]; i++)
995+
for (i = 0; deltaenv && deltaenv[i] && *deltaenv[i]; i++)
989996
size = do_putenv(tmpenv, deltaenv[i], size, 0);
990997

991998
/* create environment block from temporary environment */
992-
for (i = 0; tmpenv[i]; i++) {
999+
for (i = 0; tmpenv[i] && *tmpenv[i]; i++) {
9931000
size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
9941001
ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
9951002
wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
@@ -1278,6 +1285,41 @@ static int compareenv(const void *v1, const void *v2)
12781285
}
12791286
}
12801287

1288+
/*
1289+
* Functions implemented outside Git are able to modify the environment,
1290+
* too. For example, cURL's curl_global_init() function sets the CHARSET
1291+
* environment variable (at least in certain circumstances).
1292+
*
1293+
* Therefore we need to be *really* careful *not* to assume that we have
1294+
* sole control over the environment and reinitalize it when necessary.
1295+
*/
1296+
static void maybe_reinitialize_environ(void)
1297+
{
1298+
int i;
1299+
1300+
if (!saved_environ) {
1301+
warning("MinGW environment not initialized yet");
1302+
return;
1303+
}
1304+
1305+
if (environ_size <= 0)
1306+
return;
1307+
1308+
if (saved_environ != environ)
1309+
/* We have *no* idea how much space was allocated outside */
1310+
environ_alloc = 0;
1311+
else if (!environ[environ_size - 1])
1312+
return; /* still consistent */
1313+
1314+
for (i = 0; environ[i] && *environ[i]; i++)
1315+
; /* continue counting */
1316+
environ[i] = NULL;
1317+
environ_size = i + 1;
1318+
1319+
/* sort environment for O(log n) getenv / putenv */
1320+
qsort(environ, i, sizeof(char*), compareenv);
1321+
}
1322+
12811323
static int bsearchenv(char **env, const char *name, size_t size)
12821324
{
12831325
unsigned low = 0, high = size;
@@ -1301,7 +1343,7 @@ static int bsearchenv(char **env, const char *name, size_t size)
13011343
*/
13021344
static int do_putenv(char **env, const char *name, int size, int free_old)
13031345
{
1304-
int i = bsearchenv(env, name, size - 1);
1346+
int i = size <= 0 ? -1 : bsearchenv(env, name, size - 1);
13051347

13061348
/* optionally free removed / replaced entry */
13071349
if (i >= 0 && free_old)
@@ -1326,7 +1368,14 @@ static int do_putenv(char **env, const char *name, int size, int free_old)
13261368
char *mingw_getenv(const char *name)
13271369
{
13281370
char *value;
1329-
int pos = bsearchenv(environ, name, environ_size - 1);
1371+
int pos;
1372+
1373+
if (environ_size <= 0)
1374+
return NULL;
1375+
1376+
maybe_reinitialize_environ();
1377+
pos = bsearchenv(environ, name, environ_size - 1);
1378+
13301379
if (pos < 0)
13311380
return NULL;
13321381
value = strchr(environ[pos], '=');
@@ -1335,7 +1384,9 @@ char *mingw_getenv(const char *name)
13351384

13361385
int mingw_putenv(const char *namevalue)
13371386
{
1387+
maybe_reinitialize_environ();
13381388
ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
1389+
saved_environ = environ;
13391390
environ_size = do_putenv(environ, namevalue, environ_size, 1);
13401391
return 0;
13411392
}
@@ -2223,7 +2274,7 @@ void mingw_startup()
22232274
*/
22242275
environ_size = i + 1;
22252276
environ_alloc = alloc_nr(environ_size * sizeof(char*));
2226-
environ = malloc_startup(environ_alloc);
2277+
saved_environ = environ = malloc_startup(environ_alloc);
22272278

22282279
/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
22292280
maxlen = 3 * maxlen + 1;

0 commit comments

Comments
 (0)