From dfc3da8d6fda0ff93326c801727a7d619edea9c1 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 9 Jan 2023 12:42:28 +0100 Subject: [PATCH] deps: upgrade to libuv 1.44.2 https://github.com/nodejs/node/pull/42340 --- patches/node/.patches | 12 - ...imum_supported_version_to_10_15_3406.patch | 25 - ...o_change_option_to_uv_loop_configure.patch | 207 ++-- ...acos_avoid_posix_spawnp_cwd_bug_3597.patch | 111 --- ..._don_t_use_thread-unsafe_strtok_3524.patch | 54 -- ...handle_kevent_note_exit_failure_3451.patch | 70 -- ...rocess_fix_hang_after_note_exit_3521.patch | 158 ---- ...or_for_exit_with_kqueue_on_bsds_3441.patch | 170 ---- ..._dupfd_cloexec_if_it_is_defined_3512.patch | 54 -- ...e_signal_mask_if_the_fork_fails_3537.patch | 36 - ...ess_simplify_uv_write_int_calls_3519.patch | 63 -- ...use_posix_spawn_instead_of_fork_3257.patch | 889 ------------------ .../unix_remove_uv_cloexec_ioctl_3515.patch | 91 -- .../unix_simplify_uv_cloexec_fcntl_3492.patch | 36 - 14 files changed, 94 insertions(+), 1882 deletions(-) delete mode 100644 patches/node/darwin_bump_minimum_supported_version_to_10_15_3406.patch delete mode 100644 patches/node/macos_avoid_posix_spawnp_cwd_bug_3597.patch delete mode 100644 patches/node/macos_don_t_use_thread-unsafe_strtok_3524.patch delete mode 100644 patches/node/process_bsd_handle_kevent_note_exit_failure_3451.patch delete mode 100644 patches/node/process_fix_hang_after_note_exit_3521.patch delete mode 100644 patches/node/process_monitor_for_exit_with_kqueue_on_bsds_3441.patch delete mode 100644 patches/node/process_only_use_f_dupfd_cloexec_if_it_is_defined_3512.patch delete mode 100644 patches/node/process_reset_the_signal_mask_if_the_fork_fails_3537.patch delete mode 100644 patches/node/process_simplify_uv_write_int_calls_3519.patch delete mode 100644 patches/node/reland_macos_use_posix_spawn_instead_of_fork_3257.patch delete mode 100644 patches/node/unix_remove_uv_cloexec_ioctl_3515.patch delete mode 100644 patches/node/unix_simplify_uv_cloexec_fcntl_3492.patch diff --git a/patches/node/.patches b/patches/node/.patches index b435ebacc05d0..3c3a10b2a2b4b 100644 --- a/patches/node/.patches +++ b/patches/node/.patches @@ -16,21 +16,9 @@ repl_fix_crash_when_sharedarraybuffer_disabled.patch fix_readbarrier_undefined_symbol_error_on_woa_arm64.patch fix_suppress_clang_-wdeprecated-declarations_in_libuv.patch fix_serdes_test.patch -darwin_bump_minimum_supported_version_to_10_15_3406.patch be_compatible_with_cppgc.patch feat_add_knostartdebugsignalhandler_to_environment_to_prevent.patch -process_monitor_for_exit_with_kqueue_on_bsds_3441.patch -process_bsd_handle_kevent_note_exit_failure_3451.patch -reland_macos_use_posix_spawn_instead_of_fork_3257.patch -process_reset_the_signal_mask_if_the_fork_fails_3537.patch -process_only_use_f_dupfd_cloexec_if_it_is_defined_3512.patch -unix_simplify_uv_cloexec_fcntl_3492.patch -unix_remove_uv_cloexec_ioctl_3515.patch -process_simplify_uv_write_int_calls_3519.patch -macos_don_t_use_thread-unsafe_strtok_3524.patch -process_fix_hang_after_note_exit_3521.patch feat_add_uv_loop_interrupt_on_io_change_option_to_uv_loop_configure.patch -macos_avoid_posix_spawnp_cwd_bug_3597.patch json_parse_errors_made_user-friendly.patch support_v8_sandboxed_pointers.patch build_ensure_v8_pointer_compression_sandbox_is_enabled_on_64bit.patch diff --git a/patches/node/darwin_bump_minimum_supported_version_to_10_15_3406.patch b/patches/node/darwin_bump_minimum_supported_version_to_10_15_3406.patch deleted file mode 100644 index 555ee607137d1..0000000000000 --- a/patches/node/darwin_bump_minimum_supported_version_to_10_15_3406.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Noordhuis -Date: Tue, 8 Feb 2022 14:18:29 +0100 -Subject: darwin: bump minimum supported version to 10.15 (#3406) - -We can't realistically claim to support 10.7 or any version that Apple -no longer supports so let's bump the baseline to something more -realistic. - -Refs: https://github.com/libuv/libuv/pull/482 -Refs: https://github.com/libuv/libuv/pull/3405 - -diff --git a/deps/uv/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md -index 87e23823ad6424526fdbc2457e535875124b31cb..79509db5b17bb9e7fe245d8a0fd7fa25f8665426 100644 ---- a/deps/uv/SUPPORTED_PLATFORMS.md -+++ b/deps/uv/SUPPORTED_PLATFORMS.md -@@ -3,7 +3,7 @@ - | System | Support type | Supported versions | Notes | - |---|---|---|---| - | GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | --| macOS | Tier 1 | macOS >= 10.7 | | -+| macOS | Tier 1 | macOS >= 10.15 | Current and previous macOS release | - | Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported | - | FreeBSD | Tier 1 | >= 10 | | - | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | diff --git a/patches/node/feat_add_uv_loop_interrupt_on_io_change_option_to_uv_loop_configure.patch b/patches/node/feat_add_uv_loop_interrupt_on_io_change_option_to_uv_loop_configure.patch index a568f9f86ab4a..a2b17b5174788 100644 --- a/patches/node/feat_add_uv_loop_interrupt_on_io_change_option_to_uv_loop_configure.patch +++ b/patches/node/feat_add_uv_loop_interrupt_on_io_change_option_to_uv_loop_configure.patch @@ -242,61 +242,51 @@ index e53a0f8e28637a58ceec7852d1a79874fc1a9548..dd4065c1cc68763bfe258492e3119669 return -1; } diff --git a/deps/uv/test/test-embed.c b/deps/uv/test/test-embed.c -index c6ddceb149d9c1d68b0dd17b6dac0d4c3c3e9dbc..f6572c5dc2b6ef39bd11889ad1f7873007a6437d 100644 +index 1d3355fdc6..77a63dbb4d 100644 --- a/deps/uv/test/test-embed.c +++ b/deps/uv/test/test-embed.c -@@ -25,115 +25,179 @@ +@@ -25,54 +25,184 @@ #include #include --#ifndef HAVE_KQUEUE --# if defined(__APPLE__) || \ -- defined(__DragonFly__) || \ -- defined(__FreeBSD__) || \ -- defined(__FreeBSD_kernel__) || \ -- defined(__OpenBSD__) || \ -- defined(__NetBSD__) --# define HAVE_KQUEUE 1 --# endif --#endif -- - #ifndef HAVE_EPOLL - # if defined(__linux__) - # define HAVE_EPOLL 1 - # endif +-#if !defined(_WIN32) && !defined(_AIX) +-#include ++#ifndef HAVE_EPOLL ++# if defined(__linux__) ++# define HAVE_EPOLL 1 ++# endif #endif --#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) +-static uv_async_t async; +-static uv_barrier_t barrier; +#if defined(HAVE_EPOLL) +# include +#endif - --#if defined(HAVE_KQUEUE) ++ +#if !defined(_WIN32) - # include --# include - # include - #endif ++# include ++# include ++#endif --#if defined(HAVE_EPOLL) --# include --#endif -- +static uv_loop_t main_loop; +static uv_loop_t external_loop; - static uv_thread_t embed_thread; - static uv_sem_t embed_sem; --static uv_timer_t embed_timer; - static uv_async_t embed_async; ++static uv_thread_t embed_thread; ++static uv_sem_t embed_sem; ++static uv_async_t embed_async; +static uv_async_t main_async; - static volatile int embed_closed; ++static volatile int embed_closed; --static int embed_timer_called; +-static void thread_main(void* arg) { +- ASSERT_LE(0, uv_barrier_wait(&barrier)); +- uv_sleep(250); +- ASSERT_EQ(0, uv_async_send(&async)); +-} +static uv_timer_t main_timer; +static int main_timer_called; --static void embed_thread_runner(void* arg) { +-static void async_cb(uv_async_t* handle) { +- uv_close((uv_handle_t*) handle, NULL); +#if defined(_WIN32) +static void embed_thread_poll_win(HANDLE iocp, int timeout) { + DWORD bytes; @@ -318,8 +308,7 @@ index c6ddceb149d9c1d68b0dd17b6dac0d4c3c3e9dbc..f6572c5dc2b6ef39bd11889ad1f78730 +} +#else +static void embed_thread_poll_unix(int fd, int timeout) { - int r; -- int fd; ++ int r; + do { +#if defined(HAVE_EPOLL) + struct epoll_event ev; @@ -336,113 +325,103 @@ index c6ddceb149d9c1d68b0dd17b6dac0d4c3c3e9dbc..f6572c5dc2b6ef39bd11889ad1f78730 + r = select(fd + 1, &readset, NULL, NULL, timeout >= 0 ? &tv : NULL); +#endif + } while (r == -1 && errno == EINTR); -+} + } +#endif /* !_WIN32 */ -+ -+ -+static void embed_thread_runner(void* arg) { - int timeout; -- while (!embed_closed) { -- fd = uv_backend_fd(uv_default_loop()); -- timeout = uv_backend_timeout(uv_default_loop()); + +-TEST_IMPL(embed) { +- uv_thread_t thread; +- uv_loop_t* loop; - -- do { --#if defined(HAVE_KQUEUE) -- struct timespec ts; -- ts.tv_sec = timeout / 1000; -- ts.tv_nsec = (timeout % 1000) * 1000000; -- r = kevent(fd, NULL, 0, NULL, 0, &ts); --#elif defined(HAVE_EPOLL) -- { -- struct epoll_event ev; -- r = epoll_wait(fd, &ev, 1, timeout); -- } -+ do { +- loop = uv_default_loop(); +- ASSERT_EQ(0, uv_async_init(loop, &async, async_cb)); +- ASSERT_EQ(0, uv_barrier_init(&barrier, 2)); +- ASSERT_EQ(0, uv_thread_create(&thread, thread_main, NULL)); +- ASSERT_LE(0, uv_barrier_wait(&barrier)); +- +- while (uv_loop_alive(loop)) { +-#if defined(_WIN32) || defined(_AIX) +- ASSERT_LE(0, uv_run(loop, UV_RUN_ONCE)); ++static void embed_thread_runner(void* arg) { ++ int timeout; ++ ++ while (1) { ++ uv_sem_wait(&embed_sem); ++ if (embed_closed) ++ break; ++ + timeout = uv_backend_timeout(&main_loop); + +#if defined(_WIN32) + embed_thread_poll_win(main_loop.iocp, timeout); -+#else + #else +- int rc; +- do { +- struct pollfd p; +- p.fd = uv_backend_fd(loop); +- p.events = POLLIN; +- p.revents = 0; +- rc = poll(&p, 1, uv_backend_timeout(loop)); +- } while (rc == -1 && errno == EINTR); +- ASSERT_LE(0, uv_run(loop, UV_RUN_NOWAIT)); + embed_thread_poll_unix(uv_backend_fd(&main_loop), timeout); #endif -- } while (r == -1 && errno == EINTR); + - uv_async_send(&embed_async); ++ uv_async_send(&embed_async); + } ++} ++ + - uv_sem_wait(&embed_sem); -- } -+ } while (!embed_closed); - } - - - static void embed_cb(uv_async_t* async) { -- uv_run(uv_default_loop(), UV_RUN_ONCE); ++static void embed_cb(uv_async_t* async) { + /* Run tasks in main loop */ + uv_run(&main_loop, UV_RUN_NOWAIT); - ++ + /* Tell embed thread to continue polling */ - uv_sem_post(&embed_sem); - } - - --static void embed_timer_cb(uv_timer_t* timer) { -- embed_timer_called++; ++ uv_sem_post(&embed_sem); ++} ++ ++ +static void main_timer_cb(uv_timer_t* timer) { + main_timer_called++; - embed_closed = 1; - - uv_close((uv_handle_t*) &embed_async, NULL); ++ embed_closed = 1; ++ ++ uv_close((uv_handle_t*) &embed_async, NULL); + uv_close((uv_handle_t*) &main_async, NULL); - } --#endif - - --TEST_IMPL(embed) { --#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) -- uv_loop_t external; -- -- ASSERT(0 == uv_loop_init(&external)); ++} ++ ++ +static void init_loops(void) { + ASSERT_EQ(0, uv_loop_init(&main_loop)); + ASSERT_EQ(0, uv_loop_init(&external_loop)); - -- embed_timer_called = 0; ++ + main_timer_called = 0; - embed_closed = 0; - -- uv_async_init(&external, &embed_async, embed_cb); ++ embed_closed = 0; ++ + uv_async_init(&external_loop, &embed_async, embed_cb); - -- /* Start timer in default loop */ -- uv_timer_init(uv_default_loop(), &embed_timer); -- uv_timer_start(&embed_timer, embed_timer_cb, 250, 0); ++ + /* Create a dummy async for main loop otherwise backend timeout will + always be 0 */ + uv_async_init(&main_loop, &main_async, embed_cb); - -- /* Start worker that will interrupt external loop */ ++ + /* Start worker that will poll main loop and interrupt external loop */ - uv_sem_init(&embed_sem, 0); - uv_thread_create(&embed_thread, embed_thread_runner, NULL); ++ uv_sem_init(&embed_sem, 0); ++ uv_thread_create(&embed_thread, embed_thread_runner, NULL); +} - -- /* But run external loop */ -- uv_run(&external, UV_RUN_DEFAULT); ++ + +static void run_loop(void) { ++ /* Run main loop for once to give things a chance to initialize */ ++ embed_cb(&embed_async); ++ + /* Run external loop */ + uv_run(&external_loop, UV_RUN_DEFAULT); - - uv_thread_join(&embed_thread); -- uv_loop_close(&external); ++ ++ uv_thread_join(&embed_thread); + uv_sem_destroy(&embed_sem); + uv_loop_close(&external_loop); + uv_loop_close(&main_loop); +} - -- ASSERT(embed_timer_called == 1); --#endif ++ + +TEST_IMPL(embed) { + init_loops(); @@ -478,17 +457,19 @@ index c6ddceb149d9c1d68b0dd17b6dac0d4c3c3e9dbc..f6572c5dc2b6ef39bd11889ad1f78730 + polling in embed thread */ + uv_timer_init(&external_loop, &external_timer); + uv_timer_start(&external_timer, external_timer_cb, 100, 0); -+ + +- ASSERT_EQ(0, uv_thread_join(&thread)); +- uv_barrier_destroy(&barrier); + run_loop(); + ASSERT_EQ(main_timer_called, 1); + MAKE_VALGRIND_HAPPY(); return 0; - } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index a43edf1a4a9b0932ec73b8edaca0f676ecf3ccfa..199402e31406cf8ba360d54769461bb5285011ee 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h -@@ -263,6 +263,7 @@ TEST_DECLARE (process_priority) +@@ -265,6 +265,7 @@ TEST_DECLARE (process_priority) TEST_DECLARE (has_ref) TEST_DECLARE (active) TEST_DECLARE (embed) @@ -496,7 +477,7 @@ index a43edf1a4a9b0932ec73b8edaca0f676ecf3ccfa..199402e31406cf8ba360d54769461bb5 TEST_DECLARE (async) TEST_DECLARE (async_null_cb) TEST_DECLARE (eintr_handling) -@@ -860,6 +861,7 @@ TASK_LIST_START +@@ -867,6 +868,7 @@ TASK_LIST_START TEST_ENTRY (active) TEST_ENTRY (embed) diff --git a/patches/node/macos_avoid_posix_spawnp_cwd_bug_3597.patch b/patches/node/macos_avoid_posix_spawnp_cwd_bug_3597.patch deleted file mode 100644 index f05f9ee5186e0..0000000000000 --- a/patches/node/macos_avoid_posix_spawnp_cwd_bug_3597.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jameson Nash -Date: Fri, 15 Apr 2022 14:10:27 -0400 -Subject: 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. - -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index c8816b85b7e531648064e739fb89257565ad64bb..de51bac3d0e8daf519d35c6a3994f1479590607a 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -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; -diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h -index 199402e31406cf8ba360d54769461bb5285011ee..f8c08a4a7eb164ffff495c81e1f5df712084648b 100644 ---- a/deps/uv/test/test-list.h -+++ b/deps/uv/test/test-list.h -@@ -322,6 +322,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) -@@ -954,6 +955,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) -diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c -index dfd5458ef37c664af9a55a8383bdb3121885db3b..de9c710020ef7da66e45f5617a8a697e698fa202 100644 ---- a/deps/uv/test/test-spawn.c -+++ b/deps/uv/test/test-spawn.c -@@ -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; -+} diff --git a/patches/node/macos_don_t_use_thread-unsafe_strtok_3524.patch b/patches/node/macos_don_t_use_thread-unsafe_strtok_3524.patch deleted file mode 100644 index 69e57568216d0..0000000000000 --- a/patches/node/macos_don_t_use_thread-unsafe_strtok_3524.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Noordhuis -Date: Wed, 9 Mar 2022 11:06:39 +0100 -Subject: macos: don't use thread-unsafe strtok() (#3524) - -Refs https://github.com/libuv/libuv/pull/3524 - -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index 8cde389b826b6b167437845eccd5fed440dcadc4..147164e7ea25abbf655452930d78ee0a714cce36 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -387,30 +387,22 @@ static void uv__spawn_init_posix_spawn_fncs(void) { - - - static void uv__spawn_init_can_use_setsid(void) { -- static const int MACOS_CATALINA_VERSION_MAJOR = 19; -- char version_str[256]; -- char* version_major_str; -- size_t version_str_size = 256; -- int r; -- int version_major; -- -- /* Get a version string */ -- r = sysctlbyname("kern.osrelease", version_str, &version_str_size, NULL, 0); -- if (r != 0) -+ int which[] = {CTL_KERN, KERN_OSRELEASE}; -+ unsigned major; -+ unsigned minor; -+ unsigned patch; -+ char buf[256]; -+ size_t len; -+ -+ len = sizeof(buf); -+ if (sysctl(which, ARRAY_SIZE(which), buf, &len, NULL, 0)) - return; - -- /* Try to get the major version number. If not found -- * fall back to the fork/exec flow */ -- version_major_str = strtok(version_str, "."); -- if (version_major_str == NULL) -+ /* NULL specifies to use LC_C_LOCALE */ -+ if (3 != sscanf_l(buf, NULL, "%u.%u.%u", &major, &minor, &patch)) - return; - -- /* Parse the version major as a number. If it is greater than -- * the major version for macOS Catalina (aka macOS 10.15), then -- * the POSIX_SPAWN_SETSID flag is available */ -- version_major = atoi_l(version_major_str, NULL); /* Use LC_C_LOCALE */ -- if (version_major >= MACOS_CATALINA_VERSION_MAJOR) -- posix_spawn_can_use_setsid = 1; -+ posix_spawn_can_use_setsid = (major >= 19); /* macOS Catalina */ - } - - diff --git a/patches/node/process_bsd_handle_kevent_note_exit_failure_3451.patch b/patches/node/process_bsd_handle_kevent_note_exit_failure_3451.patch deleted file mode 100644 index b8b4e9ef2541c..0000000000000 --- a/patches/node/process_bsd_handle_kevent_note_exit_failure_3451.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jameson Nash -Date: Tue, 1 Feb 2022 15:27:12 -0500 -Subject: process,bsd: handle kevent NOTE_EXIT failure (#3451) - -The kernel may return ESRCH if the child has already exited here. -This is rather annoying, and means we must indirectly handle -notification to our event loop of the process exit. - -Refs: https://github.com/libuv/libuv/pull/3441 -Refs: https://github.com/libuv/libuv/pull/3257 - -diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h -index 16be13b99f5db77741aa276e90a437ef4eb5ba32..2dcc8b32f5165dd75061a1b55cc1abd2ab93ccc9 100644 ---- a/deps/uv/src/unix/internal.h -+++ b/deps/uv/src/unix/internal.h -@@ -145,7 +145,8 @@ typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; - - /* loop flags */ - enum { -- UV_LOOP_BLOCK_SIGPROF = 1 -+ UV_LOOP_BLOCK_SIGPROF = 0x1, -+ UV_LOOP_REAP_CHILDREN = 0x2 - }; - - /* flags of excluding ifaddr */ -diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c -index efbc561dee2574f06ebd9408d1e89e435c93cc5a..857eb1d54bfde99754ce2c6e92a287c288bd9f52 100644 ---- a/deps/uv/src/unix/kqueue.c -+++ b/deps/uv/src/unix/kqueue.c -@@ -285,7 +285,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { - for (i = 0; i < nfds; i++) { - ev = events + i; - if (ev->filter == EVFILT_PROC) { -- uv__wait_children(loop); -+ loop->flags |= UV_LOOP_REAP_CHILDREN; - nevents++; - continue; - } -@@ -382,6 +382,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { - nevents++; - } - -+ if (loop->flags & UV_LOOP_REAP_CHILDREN) { -+ loop->flags &= ~UV_LOOP_REAP_CHILDREN; -+ uv__wait_children(loop); -+ } -+ - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index c1f6bd4b0076f0835caf83c45a6a896e7ae5def9..2920b942962357827bae9bcad23af8333e8b007f 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -507,8 +507,12 @@ int uv_spawn(uv_loop_t* loop, - #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - struct kevent event; - EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0); -- if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) -- abort(); -+ if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) { -+ if (errno != ESRCH) -+ abort(); -+ /* Process already exited. Call waitpid on the next loop iteration. */ -+ loop->flags |= UV_LOOP_REAP_CHILDREN; -+ } - #endif - - QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); diff --git a/patches/node/process_fix_hang_after_note_exit_3521.patch b/patches/node/process_fix_hang_after_note_exit_3521.patch deleted file mode 100644 index 768eda13452b3..0000000000000 --- a/patches/node/process_fix_hang_after_note_exit_3521.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jameson Nash -Date: Wed, 23 Mar 2022 15:39:38 +0900 -Subject: process: fix hang after NOTE_EXIT (#3521) - -Bug #3504 seems to affect more platforms than just OpenBSD. As this -seems to be a race condition in these kernels, we do not want to fail -because of it. Instead, we remove the WNOHANG flag from waitpid, and -track exactly which processes have exited. Should also be a slight speed -improvement for excessively large numbers of live children. - -diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c -index 857eb1d54bfde99754ce2c6e92a287c288bd9f52..036055149fcabcb9ff8f43522120c82b3474ab99 100644 ---- a/deps/uv/src/unix/kqueue.c -+++ b/deps/uv/src/unix/kqueue.c -@@ -117,6 +117,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { - unsigned int revents; - QUEUE* q; - uv__io_t* w; -+ uv_process_t* process; - sigset_t* pset; - sigset_t set; - uint64_t base; -@@ -284,12 +285,22 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { - loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; - for (i = 0; i < nfds; i++) { - ev = events + i; -+ fd = ev->ident; -+ -+ /* Handle kevent NOTE_EXIT results */ - if (ev->filter == EVFILT_PROC) { -- loop->flags |= UV_LOOP_REAP_CHILDREN; -+ QUEUE_FOREACH(q, &loop->process_handles) { -+ process = QUEUE_DATA(q, uv_process_t, queue); -+ if (process->pid == fd) { -+ process->flags |= UV_HANDLE_REAP; -+ loop->flags |= UV_LOOP_REAP_CHILDREN; -+ break; -+ } -+ } - nevents++; - continue; - } -- fd = ev->ident; -+ - /* Skip invalidated events, see uv__platform_invalidate_fd */ - if (fd == -1) - continue; -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index 147164e7ea25abbf655452930d78ee0a714cce36..c8816b85b7e531648064e739fb89257565ad64bb 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -63,12 +63,18 @@ extern char **environ; - # include "zos-base.h" - #endif - --#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -+#if defined(__APPLE__) || \ -+ defined(__DragonFly__) || \ -+ defined(__FreeBSD__) || \ -+ defined(__NetBSD__) || \ -+ defined(__OpenBSD__) - #include -+#else -+#define UV_USE_SIGCHLD - #endif - - --#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) -+#ifdef UV_USE_SIGCHLD - static void uv__chld(uv_signal_t* handle, int signum) { - assert(signum == SIGCHLD); - uv__wait_children(handle->loop); -@@ -80,6 +86,7 @@ void uv__wait_children(uv_loop_t* loop) { - int exit_status; - int term_signal; - int status; -+ int options; - pid_t pid; - QUEUE pending; - QUEUE* q; -@@ -93,19 +100,33 @@ void uv__wait_children(uv_loop_t* loop) { - process = QUEUE_DATA(q, uv_process_t, queue); - q = QUEUE_NEXT(q); - -+#ifndef UV_USE_SIGCHLD -+ if ((process->flags & UV_HANDLE_REAP) == 0) -+ continue; -+ options = 0; -+ process->flags &= ~UV_HANDLE_REAP; -+#else -+ options = WNOHANG; -+#endif -+ - do -- pid = waitpid(process->pid, &status, WNOHANG); -+ pid = waitpid(process->pid, &status, options); - while (pid == -1 && errno == EINTR); - -- if (pid == 0) -+#ifdef UV_USE_SIGCHLD -+ if (pid == 0) /* Not yet exited */ - continue; -+#endif - - if (pid == -1) { - if (errno != ECHILD) - abort(); -+ /* The child died, and we missed it. This probably means someone else -+ * stole the waitpid from us. Handle this by not handling it at all. */ - continue; - } - -+ assert(pid == process->pid); - process->status = status; - QUEUE_REMOVE(&process->queue); - QUEUE_INSERT_TAIL(&pending, &process->queue); -@@ -964,7 +985,7 @@ int uv_spawn(uv_loop_t* loop, - goto error; - } - --#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) -+#ifdef UV_USE_SIGCHLD - uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); - #endif - -@@ -983,13 +1004,14 @@ int uv_spawn(uv_loop_t* loop, - * fail to open a stdio handle. This ensures we can eventually reap the child - * with waitpid. */ - if (exec_errorno == 0) { --#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -+#ifndef UV_USE_SIGCHLD - struct kevent event; - EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0); - if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) { - if (errno != ESRCH) - abort(); - /* Process already exited. Call waitpid on the next loop iteration. */ -+ process->flags |= UV_HANDLE_REAP; - loop->flags |= UV_LOOP_REAP_CHILDREN; - } - #endif -diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h -index 8a190bf8fa8c5a282feaf251aec2a30c95776888..6001b0cf68d0b0268b578218b664a737f43c9521 100644 ---- a/deps/uv/src/uv-common.h -+++ b/deps/uv/src/uv-common.h -@@ -130,7 +130,10 @@ enum { - UV_SIGNAL_ONE_SHOT = 0x02000000, - - /* Only used by uv_poll_t handles. */ -- UV_HANDLE_POLL_SLOW = 0x01000000 -+ UV_HANDLE_POLL_SLOW = 0x01000000, -+ -+ /* Only used by uv_process_t handles. */ -+ UV_HANDLE_REAP = 0x10000000 - }; - - int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); diff --git a/patches/node/process_monitor_for_exit_with_kqueue_on_bsds_3441.patch b/patches/node/process_monitor_for_exit_with_kqueue_on_bsds_3441.patch deleted file mode 100644 index 38609025d0f79..0000000000000 --- a/patches/node/process_monitor_for_exit_with_kqueue_on_bsds_3441.patch +++ /dev/null @@ -1,170 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jeremy Rose -Date: Mon, 31 Jan 2022 11:49:22 -0800 -Subject: process: monitor for exit with kqueue on BSDs (#3441) - -This adds a workaround for an xnu kernel bug that sometimes results in -SIGCHLD not being delivered. The workaround is to use kevent to listen -for EVFILT_PROC/NOTE_EXIT events instead of relying on SIGCHLD on *BSD. - -Apple rdar: FB9529664 -Refs: https://github.com/libuv/libuv/pull/3257 - -diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h -index 12d4da93686e993830a7d09e74d08191fc808f4f..16be13b99f5db77741aa276e90a437ef4eb5ba32 100644 ---- a/deps/uv/src/unix/internal.h -+++ b/deps/uv/src/unix/internal.h -@@ -282,6 +282,7 @@ uv_handle_type uv__handle_type(int fd); - FILE* uv__open_file(const char* path); - int uv__getpwuid_r(uv_passwd_t* pwd); - int uv__search_path(const char* prog, char* buf, size_t* buflen); -+void uv__wait_children(uv_loop_t* loop); - - /* random */ - int uv__random_devurandom(void* buf, size_t buflen); -diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c -index 75e9110709da8d30628449311cb916a26c775ecf..efbc561dee2574f06ebd9408d1e89e435c93cc5a 100644 ---- a/deps/uv/src/unix/kqueue.c -+++ b/deps/uv/src/unix/kqueue.c -@@ -284,6 +284,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { - loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; - for (i = 0; i < nfds; i++) { - ev = events + i; -+ if (ev->filter == EVFILT_PROC) { -+ uv__wait_children(loop); -+ nevents++; -+ continue; -+ } - fd = ev->ident; - /* Skip invalidated events, see uv__platform_invalidate_fd */ - if (fd == -1) -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index 91bf3c507022b2eddc0d36f40d73a977bf731fbc..c1f6bd4b0076f0835caf83c45a6a896e7ae5def9 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -49,10 +49,20 @@ extern char **environ; - # include "zos-base.h" - #endif - -+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -+#include -+#endif -+ - -+#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) - static void uv__chld(uv_signal_t* handle, int signum) { -+ assert(signum == SIGCHLD); -+ uv__wait_children(handle->loop); -+} -+#endif -+ -+void uv__wait_children(uv_loop_t* loop) { - uv_process_t* process; -- uv_loop_t* loop; - int exit_status; - int term_signal; - int status; -@@ -61,10 +71,7 @@ static void uv__chld(uv_signal_t* handle, int signum) { - QUEUE* q; - QUEUE* h; - -- assert(signum == SIGCHLD); -- - QUEUE_INIT(&pending); -- loop = handle->loop; - - h = &loop->process_handles; - q = QUEUE_HEAD(h); -@@ -420,7 +427,9 @@ int uv_spawn(uv_loop_t* loop, - if (err) - goto error; - -+#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) - uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); -+#endif - - /* Acquire write lock to prevent opening new fds in worker threads */ - uv_rwlock_wrlock(&loop->cloexec_lock); -@@ -495,6 +504,13 @@ int uv_spawn(uv_loop_t* loop, - - /* Only activate this handle if exec() happened successfully */ - if (exec_errorno == 0) { -+#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -+ struct kevent event; -+ EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0); -+ if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) -+ abort(); -+#endif -+ - QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); - uv__handle_start(process); - } -diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h -index 1f566861a0e2e9e29c925972155f49667bb7ce85..a43edf1a4a9b0932ec73b8edaca0f676ecf3ccfa 100644 ---- a/deps/uv/test/test-list.h -+++ b/deps/uv/test/test-list.h -@@ -320,6 +320,7 @@ TEST_DECLARE (spawn_reads_child_path) - TEST_DECLARE (spawn_inherit_streams) - TEST_DECLARE (spawn_quoted_path) - TEST_DECLARE (spawn_tcp_server) -+TEST_DECLARE (spawn_exercise_sigchld_issue) - TEST_DECLARE (fs_poll) - TEST_DECLARE (fs_poll_getpath) - TEST_DECLARE (fs_poll_close_request) -@@ -950,6 +951,7 @@ TASK_LIST_START - TEST_ENTRY (spawn_inherit_streams) - TEST_ENTRY (spawn_quoted_path) - TEST_ENTRY (spawn_tcp_server) -+ TEST_ENTRY (spawn_exercise_sigchld_issue) - TEST_ENTRY (fs_poll) - TEST_ENTRY (fs_poll_getpath) - TEST_ENTRY (fs_poll_close_request) -diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c -index 9f2eb24b2d6daf339bec12027134409cfc3b4a82..dfd5458ef37c664af9a55a8383bdb3121885db3b 100644 ---- a/deps/uv/test/test-spawn.c -+++ b/deps/uv/test/test-spawn.c -@@ -1891,6 +1891,44 @@ TEST_IMPL(spawn_quoted_path) { - #endif - } - -+TEST_IMPL(spawn_exercise_sigchld_issue) { -+ int r; -+ int i; -+ uv_process_options_t dummy_options = {0}; -+ uv_process_t dummy_processes[100]; -+ char* args[2]; -+ -+ init_process_options("spawn_helper1", exit_cb); -+ -+ r = uv_spawn(uv_default_loop(), &process, &options); -+ ASSERT_EQ(r, 0); -+ -+ // This test exercises a bug in the darwin kernel that causes SIGCHLD not to -+ // be delivered sometimes. Calling posix_spawn many times increases the -+ // likelihood of encountering this issue, so spin a few times to make this -+ // test more reliable. -+ dummy_options.file = args[0] = "program-that-had-better-not-exist"; -+ args[1] = NULL; -+ dummy_options.args = args; -+ dummy_options.exit_cb = fail_cb; -+ dummy_options.flags = 0; -+ for (i = 0; i < 100; i++) { -+ r = uv_spawn(uv_default_loop(), &dummy_processes[i], &dummy_options); -+ if (r != UV_ENOENT) -+ ASSERT_EQ(r, UV_EACCES); -+ uv_close((uv_handle_t*) &dummy_processes[i], close_cb); -+ } -+ -+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); -+ ASSERT_EQ(r, 0); -+ -+ ASSERT_EQ(exit_cb_called, 1); -+ ASSERT_EQ(close_cb_called, 101); -+ -+ MAKE_VALGRIND_HAPPY(); -+ return 0; -+} -+ - /* Helper for child process of spawn_inherit_streams */ - #ifndef _WIN32 - void spawn_stdin_stdout(void) { diff --git a/patches/node/process_only_use_f_dupfd_cloexec_if_it_is_defined_3512.patch b/patches/node/process_only_use_f_dupfd_cloexec_if_it_is_defined_3512.patch deleted file mode 100644 index 5b525fb18a5f0..0000000000000 --- a/patches/node/process_only_use_f_dupfd_cloexec_if_it_is_defined_3512.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jameson Nash -Date: Sat, 5 Mar 2022 12:52:04 -0500 -Subject: process: only use F_DUPFD_CLOEXEC if it is defined (#3512) - -We can save a syscall on most modern systems (required by POSIX 2008), -but not on all systems. - -Also handle errors from CLOEXEC. Even though fcntl does not really -define there to be any, it could theoretically be EBADF if the user -happened to pass a bad file descriptor to the same number fd (such that -no other code happened to already fail on that). - -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index d208f99be40df9f36447552daf2772c1cab1ce79..7705068730cb0536998bad7d304cb87df99b72e8 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -275,9 +275,20 @@ static void uv__process_child_init(const uv_process_options_t* options, - use_fd = pipes[fd][1]; - if (use_fd < 0 || use_fd >= fd) - continue; -+#ifdef F_DUPFD_CLOEXEC /* POSIX 2008 */ - pipes[fd][1] = fcntl(use_fd, F_DUPFD_CLOEXEC, stdio_count); -+#else -+ pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); -+#endif - if (pipes[fd][1] == -1) - uv__write_errno(error_fd); -+#ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */ -+ n = uv__cloexec_fcntl(pipes[fd][1], 1); -+ if (n) { -+ uv__write_int(error_fd, n); -+ _exit(127); -+ } -+#endif - } - - for (fd = 0; fd < stdio_count; fd++) { -@@ -300,8 +311,13 @@ static void uv__process_child_init(const uv_process_options_t* options, - } - - if (fd == use_fd) { -- if (close_fd == -1) -- uv__cloexec_fcntl(use_fd, 0); -+ if (close_fd == -1) { -+ n = uv__cloexec_fcntl(use_fd, 0); -+ if (n) { -+ uv__write_int(error_fd, n); -+ _exit(127); -+ } -+ } - } - else { - fd = dup2(use_fd, fd); diff --git a/patches/node/process_reset_the_signal_mask_if_the_fork_fails_3537.patch b/patches/node/process_reset_the_signal_mask_if_the_fork_fails_3537.patch deleted file mode 100644 index e0cd88c292b7e..0000000000000 --- a/patches/node/process_reset_the_signal_mask_if_the_fork_fails_3537.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jameson Nash -Date: Fri, 11 Mar 2022 12:05:24 -0500 -Subject: process: reset the signal mask if the fork fails (#3537) - -Fix a regression that sneaked into posix spawn changes. - -Refs: https://github.com/libuv/libuv/pull/3257 - -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index b85aa3b94edd040952e0d350a47a38d9ba8a67d3..d208f99be40df9f36447552daf2772c1cab1ce79 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -790,11 +790,6 @@ static int uv__spawn_and_init_child_fork(const uv_process_options_t* options, - - *pid = fork(); - -- if (*pid == -1) { -- /* Failed to fork */ -- return UV__ERR(errno); -- } -- - if (*pid == 0) { - /* Fork succeeded, in the child process */ - uv__process_child_init(options, stdio_count, pipes, error_fd); -@@ -804,6 +799,10 @@ static int uv__spawn_and_init_child_fork(const uv_process_options_t* options, - if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) - abort(); - -+ if (*pid == -1) -+ /* Failed to fork */ -+ return UV__ERR(errno); -+ - /* Fork succeeded, in the parent process */ - return 0; - } diff --git a/patches/node/process_simplify_uv_write_int_calls_3519.patch b/patches/node/process_simplify_uv_write_int_calls_3519.patch deleted file mode 100644 index 201c9c949d49a..0000000000000 --- a/patches/node/process_simplify_uv_write_int_calls_3519.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jameson Nash -Date: Mon, 7 Mar 2022 17:07:49 -0500 -Subject: process: simplify uv__write_int calls (#3519) - -Refs https://github.com/libuv/libuv/pull/3519 - -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index b6f9756c6a6710f5f10762b9299cc35047b98097..8cde389b826b6b167437845eccd5fed440dcadc4 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -216,16 +216,14 @@ static void uv__write_int(int fd, int val) { - n = write(fd, &val, sizeof(val)); - while (n == -1 && errno == EINTR); - -- if (n == -1 && errno == EPIPE) -- return; /* parent process has quit */ -- -- assert(n == sizeof(val)); -+ /* The write might have failed (e.g. if the parent process has died), -+ * but we have nothing left but to _exit ourself now too. */ -+ _exit(127); - } - - - static void uv__write_errno(int error_fd) { - uv__write_int(error_fd, UV__ERR(errno)); -- _exit(127); - } - - -@@ -284,10 +282,8 @@ static void uv__process_child_init(const uv_process_options_t* options, - uv__write_errno(error_fd); - #ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */ - n = uv__cloexec(pipes[fd][1], 1); -- if (n) { -+ if (n) - uv__write_int(error_fd, n); -- _exit(127); -- } - #endif - } - -@@ -313,10 +309,8 @@ static void uv__process_child_init(const uv_process_options_t* options, - if (fd == use_fd) { - if (close_fd == -1) { - n = uv__cloexec(use_fd, 0); -- if (n) { -+ if (n) - uv__write_int(error_fd, n); -- _exit(127); -- } - } - } - else { -@@ -368,7 +362,6 @@ static void uv__process_child_init(const uv_process_options_t* options, - #endif - - uv__write_errno(error_fd); -- abort(); - } - #endif - diff --git a/patches/node/reland_macos_use_posix_spawn_instead_of_fork_3257.patch b/patches/node/reland_macos_use_posix_spawn_instead_of_fork_3257.patch deleted file mode 100644 index cccbbf11736e0..0000000000000 --- a/patches/node/reland_macos_use_posix_spawn_instead_of_fork_3257.patch +++ /dev/null @@ -1,889 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jameson Nash -Date: Wed, 2 Mar 2022 15:15:39 -0500 -Subject: Reland "macos: use posix_spawn instead of fork" (#3257) - -Fixes: https://github.com/libuv/libuv/issues/3050 -Refs: https://github.com/libuv/libuv/issues/3086 -Refs: https://github.com/libuv/libuv/pull/3064 -Refs: https://github.com/libuv/libuv/pull/3107 -Refs: https://github.com/libuv/libuv/pull/3064 - -This reverts commit 217fdf4265589889d00c7c0622fde2710971a020, then fixes -several issues with it: - -* remove error fast-cleanup code that triggers a nodejs bug - -Refs: https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 - -* protect posix_spawn from EINTR - -This is not a documented valid error, but seems to have been observed. - -* ignore setuid/setgid syscall - -This kernel function is not permitted unless the process is setuid root, -so disable this syscall. Falling back to fork/exec should be okay for -the rare cases that the user decides they need to do setuid(getuid()) or -setuid(geteuid()) for the child. - -Refs: https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 - -* improve posix_spawn path search - -Ports the improvements in musl back to this function - -* fix some additional problems and formatting issues - -We previously might fail to start a watcher, in rare failure cases, -resulting in a zombie that we would fail to kill. Also avoid creating -the signal-pipe unless required (addresses a review comment from Apple) - -* fix fd->fd mapping reuse - -There was a chance that when duplicating the fd's into stdio_count+fd we -might be closing a currently opened fd with that value. - -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index 2920b942962357827bae9bcad23af8333e8b007f..b85aa3b94edd040952e0d350a47a38d9ba8a67d3 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -35,8 +36,21 @@ - #include - - #if defined(__APPLE__) && !TARGET_OS_IPHONE -+# include -+# include -+# include -+# include -+# include -+# include - # include -+# include - # define environ (*_NSGetEnviron()) -+ -+/* macOS 10.14 back does not define this constant */ -+# ifndef POSIX_SPAWN_SETSID -+# define POSIX_SPAWN_SETSID 1024 -+# endif -+ - #else - extern char **environ; - #endif -@@ -261,22 +275,22 @@ static void uv__process_child_init(const uv_process_options_t* options, - use_fd = pipes[fd][1]; - if (use_fd < 0 || use_fd >= fd) - continue; -- pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); -+ pipes[fd][1] = fcntl(use_fd, F_DUPFD_CLOEXEC, stdio_count); - if (pipes[fd][1] == -1) - uv__write_errno(error_fd); - } - - for (fd = 0; fd < stdio_count; fd++) { -- close_fd = pipes[fd][0]; -+ close_fd = -1; - use_fd = pipes[fd][1]; - - if (use_fd < 0) { - if (fd >= 3) - continue; - else { -- /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is -- * set -- */ -+ /* Redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is -+ * set. */ -+ uv__close_nocheckstdio(fd); /* Free up fd, if it happens to be open. */ - use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); - close_fd = use_fd; - -@@ -285,28 +299,24 @@ static void uv__process_child_init(const uv_process_options_t* options, - } - } - -- if (fd == use_fd) -- uv__cloexec_fcntl(use_fd, 0); -- else -+ if (fd == use_fd) { -+ if (close_fd == -1) -+ uv__cloexec_fcntl(use_fd, 0); -+ } -+ else { - fd = dup2(use_fd, fd); -+ } - - if (fd == -1) - uv__write_errno(error_fd); - -- if (fd <= 2) -+ if (fd <= 2 && close_fd == -1) - uv__nonblock_fcntl(fd, 0); - - if (close_fd >= stdio_count) - uv__close(close_fd); - } - -- for (fd = 0; fd < stdio_count; fd++) { -- use_fd = pipes[fd][1]; -- -- if (use_fd >= stdio_count) -- uv__close(use_fd); -- } -- - if (options->cwd != NULL && chdir(options->cwd)) - uv__write_errno(error_fd); - -@@ -327,9 +337,8 @@ static void uv__process_child_init(const uv_process_options_t* options, - if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) - uv__write_errno(error_fd); - -- if (options->env != NULL) { -+ if (options->env != NULL) - environ = options->env; -- } - - /* Reset signal mask just before exec. */ - sigemptyset(&signewset); -@@ -348,6 +357,562 @@ static void uv__process_child_init(const uv_process_options_t* options, - #endif - - -+#if defined(__APPLE__) -+typedef struct uv__posix_spawn_fncs_tag { -+ struct { -+ int (*addchdir_np)(const posix_spawn_file_actions_t *, const char *); -+ } file_actions; -+} uv__posix_spawn_fncs_t; -+ -+ -+static uv_once_t posix_spawn_init_once = UV_ONCE_INIT; -+static uv__posix_spawn_fncs_t posix_spawn_fncs; -+static int posix_spawn_can_use_setsid; -+ -+ -+static void uv__spawn_init_posix_spawn_fncs(void) { -+ /* Try to locate all non-portable functions at runtime */ -+ posix_spawn_fncs.file_actions.addchdir_np = -+ dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_addchdir_np"); -+} -+ -+ -+static void uv__spawn_init_can_use_setsid(void) { -+ static const int MACOS_CATALINA_VERSION_MAJOR = 19; -+ char version_str[256]; -+ char* version_major_str; -+ size_t version_str_size = 256; -+ int r; -+ int version_major; -+ -+ /* Get a version string */ -+ r = sysctlbyname("kern.osrelease", version_str, &version_str_size, NULL, 0); -+ if (r != 0) -+ return; -+ -+ /* Try to get the major version number. If not found -+ * fall back to the fork/exec flow */ -+ version_major_str = strtok(version_str, "."); -+ if (version_major_str == NULL) -+ return; -+ -+ /* Parse the version major as a number. If it is greater than -+ * the major version for macOS Catalina (aka macOS 10.15), then -+ * the POSIX_SPAWN_SETSID flag is available */ -+ version_major = atoi_l(version_major_str, NULL); /* Use LC_C_LOCALE */ -+ if (version_major >= MACOS_CATALINA_VERSION_MAJOR) -+ posix_spawn_can_use_setsid = 1; -+} -+ -+ -+static void uv__spawn_init_posix_spawn(void) { -+ /* Init handles to all potentially non-defined functions */ -+ uv__spawn_init_posix_spawn_fncs(); -+ -+ /* Init feature detection for POSIX_SPAWN_SETSID flag */ -+ uv__spawn_init_can_use_setsid(); -+} -+ -+ -+static int uv__spawn_set_posix_spawn_attrs( -+ posix_spawnattr_t* attrs, -+ const uv__posix_spawn_fncs_t* posix_spawn_fncs, -+ const uv_process_options_t* options) { -+ int err; -+ unsigned int flags; -+ sigset_t signal_set; -+ -+ err = posix_spawnattr_init(attrs); -+ if (err != 0) { -+ /* If initialization fails, no need to de-init, just return */ -+ return err; -+ } -+ -+ if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { -+ /* kauth_cred_issuser currently requires exactly uid == 0 for these -+ * posixspawn_attrs (set_groups_np, setuid_np, setgid_np), which deviates -+ * from the normal specification of setuid (which also uses euid), and they -+ * are also undocumented syscalls, so we do not use them. */ -+ err = ENOSYS; -+ goto error; -+ } -+ -+ /* Set flags for spawn behavior -+ * 1) POSIX_SPAWN_CLOEXEC_DEFAULT: (Apple Extension) All descriptors in the -+ * parent will be treated as if they had been created with O_CLOEXEC. The -+ * only fds that will be passed on to the child are those manipulated by -+ * the file actions -+ * 2) POSIX_SPAWN_SETSIGDEF: Signals mentioned in spawn-sigdefault in the -+ * spawn attributes will be reset to behave as their default -+ * 3) POSIX_SPAWN_SETSIGMASK: Signal mask will be set to the value of -+ * spawn-sigmask in attributes -+ * 4) POSIX_SPAWN_SETSID: Make the process a new session leader if a detached -+ * session was requested. */ -+ flags = POSIX_SPAWN_CLOEXEC_DEFAULT | -+ POSIX_SPAWN_SETSIGDEF | -+ POSIX_SPAWN_SETSIGMASK; -+ if (options->flags & UV_PROCESS_DETACHED) { -+ /* If running on a version of macOS where this flag is not supported, -+ * revert back to the fork/exec flow. Otherwise posix_spawn will -+ * silently ignore the flag. */ -+ if (!posix_spawn_can_use_setsid) { -+ err = ENOSYS; -+ goto error; -+ } -+ -+ flags |= POSIX_SPAWN_SETSID; -+ } -+ err = posix_spawnattr_setflags(attrs, flags); -+ if (err != 0) -+ goto error; -+ -+ /* Reset all signal the child to their default behavior */ -+ sigfillset(&signal_set); -+ err = posix_spawnattr_setsigdefault(attrs, &signal_set); -+ if (err != 0) -+ goto error; -+ -+ /* Reset the signal mask for all signals */ -+ sigemptyset(&signal_set); -+ err = posix_spawnattr_setsigmask(attrs, &signal_set); -+ if (err != 0) -+ goto error; -+ -+ return err; -+ -+error: -+ (void) posix_spawnattr_destroy(attrs); -+ return err; -+} -+ -+ -+static int uv__spawn_set_posix_spawn_file_actions( -+ posix_spawn_file_actions_t* actions, -+ const uv__posix_spawn_fncs_t* posix_spawn_fncs, -+ const uv_process_options_t* options, -+ int stdio_count, -+ int (*pipes)[2]) { -+ int fd; -+ int fd2; -+ int use_fd; -+ int err; -+ -+ err = posix_spawn_file_actions_init(actions); -+ if (err != 0) { -+ /* If initialization fails, no need to de-init, just return */ -+ return err; -+ } -+ -+ /* Set the current working directory if requested */ -+ if (options->cwd != NULL) { -+ if (posix_spawn_fncs->file_actions.addchdir_np == NULL) { -+ err = ENOSYS; -+ goto error; -+ } -+ -+ err = posix_spawn_fncs->file_actions.addchdir_np(actions, options->cwd); -+ if (err != 0) -+ goto error; -+ } -+ -+ /* Do not return ENOSYS after this point, as we may mutate pipes. */ -+ -+ /* First duplicate low numbered fds, since it's not safe to duplicate them, -+ * they could get replaced. Example: swapping stdout and stderr; without -+ * this fd 2 (stderr) would be duplicated into fd 1, thus making both -+ * stdout and stderr go to the same fd, which was not the intention. */ -+ for (fd = 0; fd < stdio_count; fd++) { -+ use_fd = pipes[fd][1]; -+ if (use_fd < 0 || use_fd >= fd) -+ continue; -+ use_fd = stdio_count; -+ for (fd2 = 0; fd2 < stdio_count; fd2++) { -+ /* If we were not setting POSIX_SPAWN_CLOEXEC_DEFAULT, we would need to -+ * also consider whether fcntl(fd, F_GETFD) returned without the -+ * FD_CLOEXEC flag set. */ -+ if (pipes[fd2][1] == use_fd) { -+ use_fd++; -+ fd2 = 0; -+ } -+ } -+ err = posix_spawn_file_actions_adddup2( -+ actions, -+ pipes[fd][1], -+ use_fd); -+ assert(err != ENOSYS); -+ if (err != 0) -+ goto error; -+ pipes[fd][1] = use_fd; -+ } -+ -+ /* Second, move the descriptors into their respective places */ -+ for (fd = 0; fd < stdio_count; fd++) { -+ use_fd = pipes[fd][1]; -+ if (use_fd < 0) { -+ if (fd >= 3) -+ continue; -+ else { -+ /* If ignored, redirect to (or from) /dev/null, */ -+ err = posix_spawn_file_actions_addopen( -+ actions, -+ fd, -+ "/dev/null", -+ fd == 0 ? O_RDONLY : O_RDWR, -+ 0); -+ assert(err != ENOSYS); -+ if (err != 0) -+ goto error; -+ continue; -+ } -+ } -+ -+ if (fd == use_fd) -+ err = posix_spawn_file_actions_addinherit_np(actions, fd); -+ else -+ err = posix_spawn_file_actions_adddup2(actions, use_fd, fd); -+ assert(err != ENOSYS); -+ if (err != 0) -+ goto error; -+ -+ /* Make sure the fd is marked as non-blocking (state shared between child -+ * and parent). */ -+ uv__nonblock_fcntl(use_fd, 0); -+ } -+ -+ /* Finally, close all the superfluous descriptors */ -+ for (fd = 0; fd < stdio_count; fd++) { -+ use_fd = pipes[fd][1]; -+ if (use_fd < stdio_count) -+ continue; -+ -+ /* Check if we already closed this. */ -+ for (fd2 = 0; fd2 < fd; fd2++) { -+ if (pipes[fd2][1] == use_fd) -+ break; -+ } -+ if (fd2 < fd) -+ continue; -+ -+ err = posix_spawn_file_actions_addclose(actions, use_fd); -+ assert(err != ENOSYS); -+ if (err != 0) -+ goto error; -+ } -+ -+ return 0; -+ -+error: -+ (void) posix_spawn_file_actions_destroy(actions); -+ return err; -+} -+ -+char* uv__spawn_find_path_in_env(char** env) { -+ char** env_iterator; -+ const char path_var[] = "PATH="; -+ -+ /* Look for an environment variable called PATH in the -+ * provided env array, and return its value if found */ -+ for (env_iterator = env; *env_iterator != NULL; env_iterator++) { -+ if (strncmp(*env_iterator, path_var, sizeof(path_var) - 1) == 0) { -+ /* Found "PATH=" at the beginning of the string */ -+ return *env_iterator + sizeof(path_var) - 1; -+ } -+ } -+ -+ return NULL; -+} -+ -+ -+static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options, -+ posix_spawnattr_t* attrs, -+ posix_spawn_file_actions_t* actions, -+ pid_t* pid) { -+ const char *p; -+ const char *z; -+ const char *path; -+ size_t l; -+ size_t k; -+ int err; -+ int seen_eacces; -+ -+ path = NULL; -+ err = -1; -+ seen_eacces = 0; -+ -+ /* Short circuit for erroneous case */ -+ if (options->file == NULL) -+ return ENOENT; -+ -+ /* The environment for the child process is that of the parent unless overriden -+ * by options->env */ -+ char** env = environ; -+ 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) { -+ do -+ err = posix_spawnp(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); -+ -+ /* 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 -+ * to look for the executable */ -+ if (path == NULL) -+ path = _PATH_DEFPATH; -+ -+ k = strnlen(options->file, NAME_MAX + 1); -+ if (k > NAME_MAX) -+ return ENAMETOOLONG; -+ -+ l = strnlen(path, PATH_MAX - 1) + 1; -+ -+ for (p = path;; p = z) { -+ /* Compose the new process file from the entry in the PATH -+ * environment variable and the actual file name */ -+ char b[PATH_MAX + NAME_MAX]; -+ z = strchr(p, ':'); -+ if (!z) -+ z = p + strlen(p); -+ if ((size_t)(z - p) >= l) { -+ if (!*z++) -+ break; -+ -+ continue; -+ } -+ memcpy(b, p, z - p); -+ b[z - p] = '/'; -+ memcpy(b + (z - p) + (z > p), options->file, k + 1); -+ -+ /* Try to spawn the new process file. If it fails with ENOENT, the -+ * new process file is not in this PATH entry, continue with the next -+ * PATH entry. */ -+ do -+ err = posix_spawn(pid, b, actions, attrs, options->args, env); -+ while (err == EINTR); -+ -+ switch (err) { -+ case EACCES: -+ seen_eacces = 1; -+ break; /* continue search */ -+ case ENOENT: -+ case ENOTDIR: -+ break; /* continue search */ -+ default: -+ return err; -+ } -+ -+ if (!*z++) -+ break; -+ } -+ -+ if (seen_eacces) -+ return EACCES; -+ return err; -+} -+ -+ -+static int uv__spawn_and_init_child_posix_spawn( -+ const uv_process_options_t* options, -+ int stdio_count, -+ int (*pipes)[2], -+ pid_t* pid, -+ const uv__posix_spawn_fncs_t* posix_spawn_fncs) { -+ int err; -+ posix_spawnattr_t attrs; -+ posix_spawn_file_actions_t actions; -+ -+ err = uv__spawn_set_posix_spawn_attrs(&attrs, posix_spawn_fncs, options); -+ if (err != 0) -+ goto error; -+ -+ /* This may mutate pipes. */ -+ err = uv__spawn_set_posix_spawn_file_actions(&actions, -+ posix_spawn_fncs, -+ options, -+ stdio_count, -+ pipes); -+ if (err != 0) { -+ (void) posix_spawnattr_destroy(&attrs); -+ goto error; -+ } -+ -+ /* Try to spawn options->file resolving in the provided environment -+ * if any */ -+ err = uv__spawn_resolve_and_spawn(options, &attrs, &actions, pid); -+ assert(err != ENOSYS); -+ -+ /* Destroy the actions/attributes */ -+ (void) posix_spawn_file_actions_destroy(&actions); -+ (void) posix_spawnattr_destroy(&attrs); -+ -+error: -+ /* In an error situation, the attributes and file actions are -+ * already destroyed, only the happy path requires cleanup */ -+ return UV__ERR(err); -+} -+#endif -+ -+static int uv__spawn_and_init_child_fork(const uv_process_options_t* options, -+ int stdio_count, -+ int (*pipes)[2], -+ int error_fd, -+ pid_t* pid) { -+ sigset_t signewset; -+ sigset_t sigoldset; -+ -+ /* Start the child with most signals blocked, to avoid any issues before we -+ * can reset them, but allow program failures to exit (and not hang). */ -+ sigfillset(&signewset); -+ sigdelset(&signewset, SIGKILL); -+ sigdelset(&signewset, SIGSTOP); -+ sigdelset(&signewset, SIGTRAP); -+ sigdelset(&signewset, SIGSEGV); -+ sigdelset(&signewset, SIGBUS); -+ sigdelset(&signewset, SIGILL); -+ sigdelset(&signewset, SIGSYS); -+ sigdelset(&signewset, SIGABRT); -+ if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0) -+ abort(); -+ -+ *pid = fork(); -+ -+ if (*pid == -1) { -+ /* Failed to fork */ -+ return UV__ERR(errno); -+ } -+ -+ if (*pid == 0) { -+ /* Fork succeeded, in the child process */ -+ uv__process_child_init(options, stdio_count, pipes, error_fd); -+ abort(); -+ } -+ -+ if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) -+ abort(); -+ -+ /* Fork succeeded, in the parent process */ -+ return 0; -+} -+ -+static int uv__spawn_and_init_child( -+ uv_loop_t* loop, -+ const uv_process_options_t* options, -+ int stdio_count, -+ int (*pipes)[2], -+ pid_t* pid) { -+ int signal_pipe[2] = { -1, -1 }; -+ int status; -+ int err; -+ int exec_errorno; -+ ssize_t r; -+ -+#if defined(__APPLE__) -+ uv_once(&posix_spawn_init_once, uv__spawn_init_posix_spawn); -+ -+ /* Special child process spawn case for macOS Big Sur (11.0) onwards -+ * -+ * Big Sur introduced a significant performance degradation on a call to -+ * fork/exec when the process has many pages mmaped in with MAP_JIT, like, say -+ * a javascript interpreter. Electron-based applications, for example, -+ * are impacted; though the magnitude of the impact depends on how much the -+ * app relies on subprocesses. -+ * -+ * On macOS, though, posix_spawn is implemented in a way that does not -+ * exhibit the problem. This block implements the forking and preparation -+ * logic with posix_spawn and its related primitives. It also takes advantage of -+ * the macOS extension POSIX_SPAWN_CLOEXEC_DEFAULT that makes impossible to -+ * leak descriptors to the child process. */ -+ err = uv__spawn_and_init_child_posix_spawn(options, -+ stdio_count, -+ pipes, -+ pid, -+ &posix_spawn_fncs); -+ -+ /* The posix_spawn flow will return UV_ENOSYS if any of the posix_spawn_x_np -+ * non-standard functions is both _needed_ and _undefined_. In those cases, -+ * default back to the fork/execve strategy. For all other errors, just fail. */ -+ if (err != UV_ENOSYS) -+ return err; -+ -+#endif -+ -+ /* This pipe is used by the parent to wait until -+ * the child has called `execve()`. We need this -+ * to avoid the following race condition: -+ * -+ * if ((pid = fork()) > 0) { -+ * kill(pid, SIGTERM); -+ * } -+ * else if (pid == 0) { -+ * execve("/bin/cat", argp, envp); -+ * } -+ * -+ * The parent sends a signal immediately after forking. -+ * Since the child may not have called `execve()` yet, -+ * there is no telling what process receives the signal, -+ * our fork or /bin/cat. -+ * -+ * To avoid ambiguity, we create a pipe with both ends -+ * marked close-on-exec. Then, after the call to `fork()`, -+ * the parent polls the read end until it EOFs or errors with EPIPE. -+ */ -+ err = uv__make_pipe(signal_pipe, 0); -+ if (err) -+ return err; -+ -+ /* Acquire write lock to prevent opening new fds in worker threads */ -+ uv_rwlock_wrlock(&loop->cloexec_lock); -+ -+ err = uv__spawn_and_init_child_fork(options, stdio_count, pipes, signal_pipe[1], pid); -+ -+ /* Release lock in parent process */ -+ uv_rwlock_wrunlock(&loop->cloexec_lock); -+ -+ uv__close(signal_pipe[1]); -+ -+ if (err == 0) { -+ do -+ r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); -+ while (r == -1 && errno == EINTR); -+ -+ if (r == 0) -+ ; /* okay, EOF */ -+ else if (r == sizeof(exec_errorno)) { -+ do -+ err = waitpid(*pid, &status, 0); /* okay, read errorno */ -+ while (err == -1 && errno == EINTR); -+ assert(err == *pid); -+ err = exec_errorno; -+ } else if (r == -1 && errno == EPIPE) { -+ /* Something unknown happened to our child before spawn */ -+ do -+ err = waitpid(*pid, &status, 0); /* okay, got EPIPE */ -+ while (err == -1 && errno == EINTR); -+ assert(err == *pid); -+ err = UV_EPIPE; -+ } else -+ abort(); -+ } -+ -+ uv__close_nocheckstdio(signal_pipe[0]); -+ -+ return err; -+} -+ - int uv_spawn(uv_loop_t* loop, - uv_process_t* process, - const uv_process_options_t* options) { -@@ -355,18 +920,13 @@ int uv_spawn(uv_loop_t* loop, - /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ - return UV_ENOSYS; - #else -- sigset_t signewset; -- sigset_t sigoldset; -- int signal_pipe[2] = { -1, -1 }; - int pipes_storage[8][2]; - int (*pipes)[2]; - int stdio_count; -- ssize_t r; - pid_t pid; - int err; - int exec_errorno; - int i; -- int status; - - assert(options->file != NULL); - assert(!(options->flags & ~(UV_PROCESS_DETACHED | -@@ -379,6 +939,7 @@ int uv_spawn(uv_loop_t* loop, - - uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); - QUEUE_INIT(&process->queue); -+ process->status = 0; - - stdio_count = options->stdio_count; - if (stdio_count < 3) -@@ -403,106 +964,24 @@ int uv_spawn(uv_loop_t* loop, - goto error; - } - -- /* This pipe is used by the parent to wait until -- * the child has called `execve()`. We need this -- * to avoid the following race condition: -- * -- * if ((pid = fork()) > 0) { -- * kill(pid, SIGTERM); -- * } -- * else if (pid == 0) { -- * execve("/bin/cat", argp, envp); -- * } -- * -- * The parent sends a signal immediately after forking. -- * Since the child may not have called `execve()` yet, -- * there is no telling what process receives the signal, -- * our fork or /bin/cat. -- * -- * To avoid ambiguity, we create a pipe with both ends -- * marked close-on-exec. Then, after the call to `fork()`, -- * the parent polls the read end until it EOFs or errors with EPIPE. -- */ -- err = uv__make_pipe(signal_pipe, 0); -- if (err) -- goto error; -- - #if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) - uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); - #endif - -- /* Acquire write lock to prevent opening new fds in worker threads */ -- uv_rwlock_wrlock(&loop->cloexec_lock); -- -- /* Start the child with most signals blocked, to avoid any issues before we -- * can reset them, but allow program failures to exit (and not hang). */ -- sigfillset(&signewset); -- sigdelset(&signewset, SIGKILL); -- sigdelset(&signewset, SIGSTOP); -- sigdelset(&signewset, SIGTRAP); -- sigdelset(&signewset, SIGSEGV); -- sigdelset(&signewset, SIGBUS); -- sigdelset(&signewset, SIGILL); -- sigdelset(&signewset, SIGSYS); -- sigdelset(&signewset, SIGABRT); -- if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0) -- abort(); -- -- pid = fork(); -- if (pid == -1) -- err = UV__ERR(errno); -- -- if (pid == 0) -- uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); -+ /* Spawn the child */ -+ exec_errorno = uv__spawn_and_init_child(loop, options, stdio_count, pipes, &pid); - -- if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) -- abort(); -- -- /* Release lock in parent process */ -- uv_rwlock_wrunlock(&loop->cloexec_lock); -- -- uv__close(signal_pipe[1]); -- -- if (pid == -1) { -- uv__close(signal_pipe[0]); -- goto error; -- } -- -- process->status = 0; -- exec_errorno = 0; -- do -- r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); -- while (r == -1 && errno == EINTR); -- -- if (r == 0) -- ; /* okay, EOF */ -- else if (r == sizeof(exec_errorno)) { -- do -- err = waitpid(pid, &status, 0); /* okay, read errorno */ -- while (err == -1 && errno == EINTR); -- assert(err == pid); -- } else if (r == -1 && errno == EPIPE) { -- do -- err = waitpid(pid, &status, 0); /* okay, got EPIPE */ -- while (err == -1 && errno == EINTR); -- assert(err == pid); -- } else -- abort(); -- -- uv__close_nocheckstdio(signal_pipe[0]); -- -- for (i = 0; i < options->stdio_count; i++) { -- err = uv__process_open_stream(options->stdio + i, pipes[i]); -- if (err == 0) -- continue; -- -- while (i--) -- uv__process_close_stream(options->stdio + i); -- -- goto error; -- } -+#if 0 -+ /* This runs into a nodejs issue (it expects initialized streams, even if the -+ * exec failed). -+ * See https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 */ -+ if (exec_errorno != 0) -+ goto error; -+#endif - -- /* Only activate this handle if exec() happened successfully */ -+ /* Activate this handle if exec() happened successfully, even if we later -+ * fail to open a stdio handle. This ensures we can eventually reap the child -+ * with waitpid. */ - if (exec_errorno == 0) { - #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - struct kevent event; -@@ -515,12 +994,22 @@ int uv_spawn(uv_loop_t* loop, - } - #endif - -+ process->pid = pid; -+ process->exit_cb = options->exit_cb; - QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); - uv__handle_start(process); - } - -- process->pid = pid; -- process->exit_cb = options->exit_cb; -+ for (i = 0; i < options->stdio_count; i++) { -+ err = uv__process_open_stream(options->stdio + i, pipes[i]); -+ if (err == 0) -+ continue; -+ -+ while (i--) -+ uv__process_close_stream(options->stdio + i); -+ -+ goto error; -+ } - - if (pipes != pipes_storage) - uv__free(pipes); diff --git a/patches/node/unix_remove_uv_cloexec_ioctl_3515.patch b/patches/node/unix_remove_uv_cloexec_ioctl_3515.patch deleted file mode 100644 index 937abe6108d84..0000000000000 --- a/patches/node/unix_remove_uv_cloexec_ioctl_3515.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jameson Nash -Date: Sun, 6 Mar 2022 15:01:33 -0500 -Subject: unix: remove uv__cloexec_ioctl() (#3515) - -Now that uv__cloexec_fcntl() is simplified -(https://github.com/libuv/libuv/pull/3492), there is no benefit to -maintaining duplicate code paths for the same thing. - -diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c -index a87b96cfc1dfdc88fa712a4fa991320ff28f2dcd..7cd3a2a954ff7d70e6ba7a6f7538648841bc54b2 100644 ---- a/deps/uv/src/unix/core.c -+++ b/deps/uv/src/unix/core.c -@@ -597,20 +597,6 @@ int uv__nonblock_ioctl(int fd, int set) { - - return 0; - } -- -- --int uv__cloexec_ioctl(int fd, int set) { -- int r; -- -- do -- r = ioctl(fd, set ? FIOCLEX : FIONCLEX); -- while (r == -1 && errno == EINTR); -- -- if (r) -- return UV__ERR(errno); -- -- return 0; --} - #endif - - -@@ -645,7 +631,7 @@ int uv__nonblock_fcntl(int fd, int set) { - } - - --int uv__cloexec_fcntl(int fd, int set) { -+int uv__cloexec(int fd, int set) { - int flags; - int r; - -diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h -index 2dcc8b32f5165dd75061a1b55cc1abd2ab93ccc9..543993989b8765247e140e9d950a25192e5e1ca5 100644 ---- a/deps/uv/src/unix/internal.h -+++ b/deps/uv/src/unix/internal.h -@@ -175,11 +175,9 @@ struct uv__stream_queued_fds_s { - defined(__linux__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) --#define uv__cloexec uv__cloexec_ioctl - #define uv__nonblock uv__nonblock_ioctl - #define UV__NONBLOCK_IS_IOCTL 1 - #else --#define uv__cloexec uv__cloexec_fcntl - #define uv__nonblock uv__nonblock_fcntl - #define UV__NONBLOCK_IS_IOCTL 0 - #endif -@@ -197,8 +195,7 @@ struct uv__stream_queued_fds_s { - #endif - - /* core */ --int uv__cloexec_ioctl(int fd, int set); --int uv__cloexec_fcntl(int fd, int set); -+int uv__cloexec(int fd, int set); - int uv__nonblock_ioctl(int fd, int set); - int uv__nonblock_fcntl(int fd, int set); - int uv__close(int fd); /* preserves errno */ -diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c -index 7705068730cb0536998bad7d304cb87df99b72e8..b6f9756c6a6710f5f10762b9299cc35047b98097 100644 ---- a/deps/uv/src/unix/process.c -+++ b/deps/uv/src/unix/process.c -@@ -283,7 +283,7 @@ static void uv__process_child_init(const uv_process_options_t* options, - if (pipes[fd][1] == -1) - uv__write_errno(error_fd); - #ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */ -- n = uv__cloexec_fcntl(pipes[fd][1], 1); -+ n = uv__cloexec(pipes[fd][1], 1); - if (n) { - uv__write_int(error_fd, n); - _exit(127); -@@ -312,7 +312,7 @@ static void uv__process_child_init(const uv_process_options_t* options, - - if (fd == use_fd) { - if (close_fd == -1) { -- n = uv__cloexec_fcntl(use_fd, 0); -+ n = uv__cloexec(use_fd, 0); - if (n) { - uv__write_int(error_fd, n); - _exit(127); diff --git a/patches/node/unix_simplify_uv_cloexec_fcntl_3492.patch b/patches/node/unix_simplify_uv_cloexec_fcntl_3492.patch deleted file mode 100644 index 13229f0466cd1..0000000000000 --- a/patches/node/unix_simplify_uv_cloexec_fcntl_3492.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Ben Noordhuis -Date: Sat, 5 Mar 2022 18:55:49 +0100 -Subject: unix: simplify uv__cloexec_fcntl() (#3492) - -FD_CLOEXEC is the only defined flag for fcntl(F_SETFD) so don't bother -getting the status of that flag first with fcntl(F_GETFD), just set it. - -diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c -index 71e9c525c4a77b8b5322e8516c58329100a8d951..a87b96cfc1dfdc88fa712a4fa991320ff28f2dcd 100644 ---- a/deps/uv/src/unix/core.c -+++ b/deps/uv/src/unix/core.c -@@ -649,21 +649,9 @@ int uv__cloexec_fcntl(int fd, int set) { - int flags; - int r; - -- do -- r = fcntl(fd, F_GETFD); -- while (r == -1 && errno == EINTR); -- -- if (r == -1) -- return UV__ERR(errno); -- -- /* Bail out now if already set/clear. */ -- if (!!(r & FD_CLOEXEC) == !!set) -- return 0; -- -+ flags = 0; - if (set) -- flags = r | FD_CLOEXEC; -- else -- flags = r & ~FD_CLOEXEC; -+ flags = FD_CLOEXEC; - - do - r = fcntl(fd, F_SETFD, flags);