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)
|
||||
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;
|
||||
|
||||
@ -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)
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user