diff --git a/src/win/process.c b/src/win/process.c index be57d906..e2b055f5 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -37,9 +37,9 @@ typedef struct env_var { const char* narrow; const WCHAR* wide; - int len; /* including null or '=' */ + size_t len; /* including null or '=' */ + DWORD value_len; int supplied; - int value_len; } env_var_t; #define E_V(str) { str "=", L##str, sizeof(str), 0, 0 } @@ -549,10 +549,10 @@ error: * issues associated with that solution; this is the caller's * char**, and modifying it is rude. */ -static void check_required_vars_contains_var(env_var_t* required, int size, +static void check_required_vars_contains_var(env_var_t* required, int count, const char* var) { int i; - for (i = 0; i < size; ++i) { + for (i = 0; i < count; ++i) { if (_strnicmp(required[i].narrow, var, required[i].len) == 0) { required[i].supplied = 1; return; @@ -572,11 +572,11 @@ static void check_required_vars_contains_var(env_var_t* required, int size, * these get defined if the input environment block does not contain any * values for them. */ -WCHAR* make_program_env(char** env_block) { +uv_err_t make_program_env(char* env_block[], WCHAR** dst_ptr) { WCHAR* dst; WCHAR* ptr; char** env; - int env_len = 1 * sizeof(WCHAR); /* room for closing null */ + size_t env_len = 1; /* room for closing null */ int len; int i; DWORD var_size; @@ -588,36 +588,53 @@ WCHAR* make_program_env(char** env_block) { }; for (env = env_block; *env; env++) { + int len; check_required_vars_contains_var(required_vars, ARRAY_SIZE(required_vars), *env); - env_len += (uv_utf8_to_utf16(*env, NULL, 0) * sizeof(WCHAR)); + + len = MultiByteToWideChar(CP_UTF8, + 0, + *env, + -1, + NULL, + 0); + if (len <= 0) { + return uv__new_sys_error(GetLastError()); + } + + env_len += len; } for (i = 0; i < ARRAY_SIZE(required_vars); ++i) { if (!required_vars[i].supplied) { - env_len += required_vars[i].len * sizeof(WCHAR); + env_len += required_vars[i].len; var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0); if (var_size == 0) { - uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); + return uv__new_sys_error(GetLastError()); } - required_vars[i].value_len = (int)var_size; - env_len += (int)var_size * sizeof(WCHAR); + required_vars[i].value_len = var_size; + env_len += var_size; } } - dst = malloc(env_len); + dst = malloc(env_len * sizeof(WCHAR)); if (!dst) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + return uv__new_artificial_error(UV_ENOMEM); } ptr = dst; for (env = env_block; *env; env++, ptr += len) { - len = uv_utf8_to_utf16(*env, ptr, (size_t)(env_len - (ptr - dst))); - if (!len) { + len = MultiByteToWideChar(CP_UTF8, + 0, + *env, + -1, + ptr, + (int) (env_len - (ptr - dst))); + if (len <= 0) { free(dst); - return NULL; + return uv__new_sys_error(GetLastError()); } } @@ -636,8 +653,11 @@ WCHAR* make_program_env(char** env_block) { } } + /* Terminate with an extra NULL. */ *ptr = L'\0'; - return dst; + + *dst_ptr = dst; + return uv_ok_; } @@ -740,7 +760,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, WCHAR* path = NULL; BOOL result; WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, - *env = NULL, *cwd = NULL; + *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; DWORD process_flags; @@ -775,6 +795,12 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, if (err.code != UV_OK) goto done; + if (options.env) { + err = make_program_env(options.env, &env); + if (err.code != UV_OK) + goto done; + } + if (options.cwd) { /* Explicit cwd */ err = uv_utf8_to_utf16_alloc(options.cwd, &cwd);