windows: read the PATH env var of the child

The unix and windows process implementations diverge in their behavior
when dealing with subprocesses that are spawned with a relative path.
With unix the *child's* PATH environment variable is read, whereas
with windows the *parent's* environment variable is read.

This commit brings the two implementation in line with respect to
their behavior of reading PATH by having both read the *child's* PATH
environment variable. This involves looking into the user-provided
environment on windows and extracting the PATH variable specifically
so it can be inspected later on.
This commit is contained in:
Alex Crichton 2014-06-24 15:39:01 -07:00 committed by Saúl Ibarra Corretgé
parent d802486232
commit c7e4b31444
3 changed files with 58 additions and 5 deletions

View File

@ -813,6 +813,20 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
return 0;
}
/*
* Attempt to find the value of the PATH environment variable in the child's
* preprocessed environment.
*
* If found, a pointer into `env` is returned. If not found, NULL is returned.
*/
static WCHAR* find_path(WCHAR *env) {
for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
if (wcsncmp(env, L"PATH=", 5) == 0)
return &env[5];
}
return NULL;
}
/*
* Called on Windows thread-pool thread to indicate that
@ -910,7 +924,7 @@ int uv_spawn(uv_loop_t* loop,
const uv_process_options_t* options) {
int i;
int err = 0;
WCHAR* path = NULL;
WCHAR* path = NULL, *alloc_path = NULL;
BOOL result;
WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
*env = NULL, *cwd = NULL;
@ -984,7 +998,8 @@ int uv_spawn(uv_loop_t* loop,
}
/* Get PATH environment variable. */
{
path = find_path(env);
if (path == NULL) {
DWORD path_len, r;
path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
@ -993,11 +1008,12 @@ int uv_spawn(uv_loop_t* loop,
goto done;
}
path = (WCHAR*) malloc(path_len * sizeof(WCHAR));
if (path == NULL) {
alloc_path = (WCHAR*) malloc(path_len * sizeof(WCHAR));
if (alloc_path == NULL) {
err = ERROR_OUTOFMEMORY;
goto done;
}
path = alloc_path;
r = GetEnvironmentVariableW(L"PATH", path, path_len);
if (r == 0 || r >= path_len) {
@ -1131,7 +1147,7 @@ int uv_spawn(uv_loop_t* loop,
free(arguments);
free(cwd);
free(env);
free(path);
free(alloc_path);
if (process->child_stdio_buffer != NULL) {
/* Clean up child stdio handles. */

View File

@ -192,6 +192,7 @@ TEST_DECLARE (spawn_stdout_to_file)
TEST_DECLARE (spawn_stdout_and_stderr_to_file)
TEST_DECLARE (spawn_auto_unref)
TEST_DECLARE (spawn_closed_process_io)
TEST_DECLARE (spawn_reads_child_path)
TEST_DECLARE (fs_poll)
TEST_DECLARE (fs_poll_getpath)
TEST_DECLARE (kill)
@ -520,6 +521,7 @@ TASK_LIST_START
TEST_ENTRY (spawn_stdout_and_stderr_to_file)
TEST_ENTRY (spawn_auto_unref)
TEST_ENTRY (spawn_closed_process_io)
TEST_ENTRY (spawn_reads_child_path)
TEST_ENTRY (fs_poll)
TEST_ENTRY (fs_poll_getpath)
TEST_ENTRY (kill)

View File

@ -1291,3 +1291,38 @@ TEST_IMPL(closed_fd_events) {
return 0;
}
#endif /* !_WIN32 */
TEST_IMPL(spawn_reads_child_path) {
int r;
int len;
char path[1024];
char *env[2] = {path, NULL};
/* Set up the process, but make sure that the file to run is relative and */
/* requires a lookup into PATH */
init_process_options("spawn_helper1", exit_cb);
options.file = "run-tests";
args[0] = "run-tests";
/* Set up the PATH env variable */
for (len = strlen(exepath);
exepath[len - 1] != '/' && exepath[len - 1] != '\\';
len--);
exepath[len] = 0;
strcpy(path, "PATH=");
strcpy(path + 5, exepath);
options.env = env;
r = uv_spawn(uv_default_loop(), &process, &options);
ASSERT(r == 0);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0);
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY();
return 0;
}