Skip to content

Commit

Permalink
macos: avoid posix_spawnp() cwd bug (libuv#3597)
Browse files Browse the repository at this point in the history
macOS 10.15 has a bug where configuring the working directory with
posix_spawn_file_actions_addchdir_np() makes posix_spawnp() fail with
ENOENT even though the executable is spawned successfully.

Co-authored-by: Ben Noordhuis <[email protected]>
  • Loading branch information
vtjnash and bnoordhuis committed Apr 15, 2022
1 parent 6dfcdb9 commit 7c9b393
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 10 deletions.
18 changes: 8 additions & 10 deletions src/unix/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -671,27 +671,25 @@ static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options,
if (options->env != NULL)
env = options->env;

/* If options->file contains a slash, posix_spawn/posix_spawnp behave
* the same, and don't involve PATH resolution at all. Otherwise, if
* options->file does not include a slash, but no custom environment is
* to be used, the environment used for path resolution as well for the
* child process is that of the parent process, so posix_spawnp is the
* way to go. */
if (strchr(options->file, '/') != NULL || options->env == NULL) {
/* If options->file contains a slash, posix_spawn/posix_spawnp should behave
* the same, and do not involve PATH resolution at all. The libc
* `posix_spawnp` provided by Apple is buggy (since 10.15), so we now emulate it
* here, per https://github.com/libuv/libuv/pull/3583. */
if (strchr(options->file, '/') != NULL) {
do
err = posix_spawnp(pid, options->file, actions, attrs, options->args, env);
err = posix_spawn(pid, options->file, actions, attrs, options->args, env);
while (err == EINTR);
return err;
}

/* Look for the definition of PATH in the provided env */
path = uv__spawn_find_path_in_env(options->env);
path = uv__spawn_find_path_in_env(env);

/* The following resolution logic (execvpe emulation) is copied from
* https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c
* and adapted to work for our specific usage */

/* If no path was provided in options->env, use the default value
/* If no path was provided in env, use the default value
* to look for the executable */
if (path == NULL)
path = _PATH_DEFPATH;
Expand Down
2 changes: 2 additions & 0 deletions test/test-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ TEST_DECLARE (spawn_inherit_streams)
TEST_DECLARE (spawn_quoted_path)
TEST_DECLARE (spawn_tcp_server)
TEST_DECLARE (spawn_exercise_sigchld_issue)
TEST_DECLARE (spawn_relative_path)
TEST_DECLARE (fs_poll)
TEST_DECLARE (fs_poll_getpath)
TEST_DECLARE (fs_poll_close_request)
Expand Down Expand Up @@ -956,6 +957,7 @@ TASK_LIST_START
TEST_ENTRY (spawn_quoted_path)
TEST_ENTRY (spawn_tcp_server)
TEST_ENTRY (spawn_exercise_sigchld_issue)
TEST_ENTRY (spawn_relative_path)
TEST_ENTRY (fs_poll)
TEST_ENTRY (fs_poll_getpath)
TEST_ENTRY (fs_poll_close_request)
Expand Down
34 changes: 34 additions & 0 deletions test/test-spawn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1981,3 +1981,37 @@ void spawn_stdin_stdout(void) {
}
}
#endif /* !_WIN32 */

TEST_IMPL(spawn_relative_path) {
char* sep;

init_process_options("spawn_helper1", exit_cb);

exepath_size = sizeof(exepath) - 2;
ASSERT_EQ(0, uv_exepath(exepath, &exepath_size));
exepath[exepath_size] = '\0';

/* Poor man's basename(3). */
sep = strrchr(exepath, '/');
if (sep == NULL)
sep = strrchr(exepath, '\\');
ASSERT_NOT_NULL(sep);

/* Split into dirname and basename and make basename relative. */
memmove(sep + 2, sep, 1 + strlen(sep));
sep[0] = '\0';
sep[1] = '.';
sep[2] = '/';

options.cwd = exepath;
options.file = options.args[0] = sep + 1;

ASSERT_EQ(0, uv_spawn(uv_default_loop(), &process, &options));
ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT));

ASSERT_EQ(1, exit_cb_called);
ASSERT_EQ(1, close_cb_called);

MAKE_VALGRIND_HAPPY();
return 0;
}

0 comments on commit 7c9b393

Please sign in to comment.