macos: avoid posix_spawnp() cwd bug (#3597)
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 <info@bnoordhuis.nl>
This commit is contained in:
parent
6dfcdb9878
commit
7c9b3938df
@ -671,27 +671,25 @@ static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options,
|
|||||||
if (options->env != NULL)
|
if (options->env != NULL)
|
||||||
env = options->env;
|
env = options->env;
|
||||||
|
|
||||||
/* If options->file contains a slash, posix_spawn/posix_spawnp behave
|
/* If options->file contains a slash, posix_spawn/posix_spawnp should behave
|
||||||
* the same, and don't involve PATH resolution at all. Otherwise, if
|
* the same, and do not involve PATH resolution at all. The libc
|
||||||
* options->file does not include a slash, but no custom environment is
|
* `posix_spawnp` provided by Apple is buggy (since 10.15), so we now emulate it
|
||||||
* to be used, the environment used for path resolution as well for the
|
* here, per https://github.com/libuv/libuv/pull/3583. */
|
||||||
* child process is that of the parent process, so posix_spawnp is the
|
if (strchr(options->file, '/') != NULL) {
|
||||||
* way to go. */
|
|
||||||
if (strchr(options->file, '/') != NULL || options->env == NULL) {
|
|
||||||
do
|
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);
|
while (err == EINTR);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look for the definition of PATH in the provided env */
|
/* 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
|
/* The following resolution logic (execvpe emulation) is copied from
|
||||||
* https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c
|
* https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c
|
||||||
* and adapted to work for our specific usage */
|
* 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 */
|
* to look for the executable */
|
||||||
if (path == NULL)
|
if (path == NULL)
|
||||||
path = _PATH_DEFPATH;
|
path = _PATH_DEFPATH;
|
||||||
|
|||||||
@ -321,6 +321,7 @@ TEST_DECLARE (spawn_inherit_streams)
|
|||||||
TEST_DECLARE (spawn_quoted_path)
|
TEST_DECLARE (spawn_quoted_path)
|
||||||
TEST_DECLARE (spawn_tcp_server)
|
TEST_DECLARE (spawn_tcp_server)
|
||||||
TEST_DECLARE (spawn_exercise_sigchld_issue)
|
TEST_DECLARE (spawn_exercise_sigchld_issue)
|
||||||
|
TEST_DECLARE (spawn_relative_path)
|
||||||
TEST_DECLARE (fs_poll)
|
TEST_DECLARE (fs_poll)
|
||||||
TEST_DECLARE (fs_poll_getpath)
|
TEST_DECLARE (fs_poll_getpath)
|
||||||
TEST_DECLARE (fs_poll_close_request)
|
TEST_DECLARE (fs_poll_close_request)
|
||||||
@ -956,6 +957,7 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (spawn_quoted_path)
|
TEST_ENTRY (spawn_quoted_path)
|
||||||
TEST_ENTRY (spawn_tcp_server)
|
TEST_ENTRY (spawn_tcp_server)
|
||||||
TEST_ENTRY (spawn_exercise_sigchld_issue)
|
TEST_ENTRY (spawn_exercise_sigchld_issue)
|
||||||
|
TEST_ENTRY (spawn_relative_path)
|
||||||
TEST_ENTRY (fs_poll)
|
TEST_ENTRY (fs_poll)
|
||||||
TEST_ENTRY (fs_poll_getpath)
|
TEST_ENTRY (fs_poll_getpath)
|
||||||
TEST_ENTRY (fs_poll_close_request)
|
TEST_ENTRY (fs_poll_close_request)
|
||||||
|
|||||||
@ -1981,3 +1981,37 @@ void spawn_stdin_stdout(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* !_WIN32 */
|
#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;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user