aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/win/util.c66
-rw-r--r--test/test-env-vars.c24
2 files changed, 76 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;
}
diff --git a/test/test-env-vars.c b/test/test-env-vars.c
index f61c1c6c..ecaba337 100644
--- a/test/test-env-vars.c
+++ b/test/test-env-vars.c
@@ -142,5 +142,29 @@ TEST_IMPL(env_vars) {
r = uv_os_unsetenv(name2);
ASSERT(r == 0);
+ for (i = 1; i <= 4; i++) {
+ size_t n;
+ char* p;
+
+ n = i * 32768;
+ size = n + 1;
+
+ p = malloc(size);
+ ASSERT_NOT_NULL(p);
+
+ memset(p, 'x', n);
+ p[n] = '\0';
+
+ ASSERT_EQ(0, uv_os_setenv(name, p));
+ ASSERT_EQ(0, uv_os_getenv(name, p, &size));
+ ASSERT_EQ(n, size);
+
+ for (n = 0; n < size; n++)
+ ASSERT_EQ('x', p[n]);
+
+ ASSERT_EQ(0, uv_os_unsetenv(name));
+ free(p);
+ }
+
return 0;
}