diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2020-04-28 20:11:10 +0200 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2020-04-28 20:11:12 +0200 |
commit | db96a61c26a88e18fd09a45d78e78add7c25a6f9 (patch) | |
tree | d69b487fa1fe835b32ab8aaafad7047ce22df91e /src | |
parent | 75c8850c91ffa93fded1c8e2a8e725e00124e4be (diff) | |
download | libuv-db96a61c26a88e18fd09a45d78e78add7c25a6f9.tar.gz libuv-db96a61c26a88e18fd09a45d78e78add7c25a6f9.zip |
win: support environment variables > 32767 chars
The Windows documentation states these should not be possible
but several people have reported that they do in fact happen.
Try with a smallish stack-allocated buffer first and switch to
a heap-allocated buffer if the first one is too small.
Fixes: https://github.com/libuv/libuv/issues/2587
PR-URL: https://github.com/libuv/libuv/pull/2589
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/win/util.c | 66 |
1 files changed, 52 insertions, 14 deletions
diff --git a/src/win/util.c b/src/win/util.c index ef5e1ccb..9e1e7f73 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -60,9 +60,6 @@ #endif -/* Maximum environment variable size, including the terminating null */ -#define MAX_ENV_VAR_LENGTH 32767 - /* A RtlGenRandom() by any other name... */ extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength); @@ -1515,7 +1512,9 @@ fail: int uv_os_getenv(const char* name, char* buffer, size_t* size) { - wchar_t var[MAX_ENV_VAR_LENGTH]; + wchar_t fastvar[512]; + wchar_t* var; + DWORD varlen; wchar_t* name_w; DWORD bufsize; size_t len; @@ -1529,25 +1528,52 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { if (r != 0) return r; - SetLastError(ERROR_SUCCESS); - len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH); + var = fastvar; + varlen = ARRAY_SIZE(fastvar); + + for (;;) { + SetLastError(ERROR_SUCCESS); + len = GetEnvironmentVariableW(name_w, var, varlen); + + if (len < varlen) + break; + + /* Try repeatedly because we might have been preempted by another thread + * modifying the environment variable just as we're trying to read it. + */ + if (var != fastvar) + uv__free(var); + + varlen = 1 + len; + var = uv__malloc(varlen * sizeof(*var)); + + if (var == NULL) { + r = UV_ENOMEM; + goto fail; + } + } + uv__free(name_w); - assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */ + name_w = NULL; if (len == 0) { r = GetLastError(); - if (r != ERROR_SUCCESS) - return uv_translate_sys_error(r); + if (r != ERROR_SUCCESS) { + r = uv_translate_sys_error(r); + goto fail; + } } /* Check how much space we need */ bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL); if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); + r = uv_translate_sys_error(GetLastError()); + goto fail; } else if (bufsize > *size) { *size = bufsize; - return UV_ENOBUFS; + r = UV_ENOBUFS; + goto fail; } /* Convert to UTF-8 */ @@ -1560,11 +1586,23 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { NULL, NULL); - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); + if (bufsize == 0) { + r = uv_translate_sys_error(GetLastError()); + goto fail; + } *size = bufsize - 1; - return 0; + r = 0; + +fail: + + if (name_w != NULL) + uv__free(name_w); + + if (var != fastvar) + uv__free(var); + + return r; } |