Skip to content

Commit

Permalink
windows: read the PATH env var of the child
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
alexcrichton authored and saghul committed Aug 6, 2014
1 parent d802486 commit c7e4b31
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 5 deletions.
26 changes: 21 additions & 5 deletions src/win/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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. */
Expand Down
2 changes: 2 additions & 0 deletions test/test-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
35 changes: 35 additions & 0 deletions test/test-spawn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit c7e4b31

Please sign in to comment.