From d34e8293331d2d15563334a1524b15f03ce0f7f5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 16 Mar 2026 17:31:07 -0400 Subject: [PATCH] test if posix_spawn works before using it broken on QEMU with glibc, for example --- src/unix/process.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/unix/process.c b/src/unix/process.c index 7325132dc..185a541dd 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -73,6 +73,7 @@ extern char **environ; static uv_once_t posix_spawn_init_once = UV_ONCE_INIT; static int posix_spawn_can_use_setsid; +static volatile int posix_spawn_works; static struct uv__posix_spawn_fncs_s { struct { @@ -449,6 +450,27 @@ static void uv__spawn_init_can_use_setsid(void) { static void uv__spawn_init_posix_spawn(void) { +#if !defined(__linux__) + posix_spawn_works = 1; +#elif !defined(__ANDROID__) + pid_t pid; + int status; + + /* Probe whether vfork()/clone(CLONE_VM) correctly shares the address space, + * i.e. a write by the child before _exit() is visible to the parent once it + * resumes. On Linux vfork() is equivalent to + * clone(CLONE_VM|CLONE_VFORK|SIGCHLD). On QEMU and WSL1, CLONE_VM is broken, + * resulting in glibc errors if we try to use posix_spawn(). */ + posix_spawn_works = 0; + pid = vfork(); + if (pid == 0) { + posix_spawn_works = 1; + _exit(0); + } + if (pid > 0) + waitpid(pid, &status, 0); +#endif + /* Try to locate all new functions at runtime. * Expected on macOS, glibc, and musl. */ posix_spawn_fncs.file_actions.addchdir = @@ -797,6 +819,9 @@ static int uv__spawn_and_init_child_posix_spawn( posix_spawnattr_t attrs; posix_spawn_file_actions_t actions; + if (!posix_spawn_works) + return UV_ENOSYS; + err = uv__spawn_set_posix_spawn_attrs(&attrs, options); if (err != 0) goto error;