Skip to content

Commit b2ec2d5

Browse files
committed
Fallback to fork() on macOS if preexec_fn is set
1 parent 2684057 commit b2ec2d5

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

uvloop/handles/process.pxd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ cdef class UVProcess(UVHandle):
3434
cdef _init_env(self, dict env)
3535
cdef _init_files(self, _stdin, _stdout, _stderr)
3636
cdef _init_options(self, list args, dict env, cwd, start_new_session,
37-
_stdin, _stdout, _stderr)
37+
_stdin, _stdout, _stderr, bint force_fork)
3838

3939
cdef _close_after_spawn(self, int fd)
4040

uvloop/handles/process.pyx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,17 @@ cdef class UVProcess(UVHandle):
4646
# callbacks have a chance to avoid casting *something* into UVHandle.
4747
self._handle.data = NULL
4848

49+
force_fork = False
50+
if system.PLATFORM_IS_APPLE and (
51+
preexec_fn is not None
52+
or not pass_fds
53+
):
54+
# see _execute_child() in CPython/subprocess.py
55+
force_fork = True
56+
4957
try:
5058
self._init_options(args, env, cwd, start_new_session,
51-
_stdin, _stdout, _stderr)
59+
_stdin, _stdout, _stderr, force_fork)
5260

5361
restore_inheritable = set()
5462
if pass_fds:
@@ -232,7 +240,7 @@ cdef class UVProcess(UVHandle):
232240
return ret
233241

234242
cdef _init_options(self, list args, dict env, cwd, start_new_session,
235-
_stdin, _stdout, _stderr):
243+
_stdin, _stdout, _stderr, bint force_fork):
236244

237245
memset(&self.options, 0, sizeof(uv.uv_process_options_t))
238246

@@ -246,6 +254,21 @@ cdef class UVProcess(UVHandle):
246254
if start_new_session:
247255
self.options.flags |= uv.UV_PROCESS_DETACHED
248256

257+
if force_fork:
258+
# This is a hack to work around the change in libuv 1.44:
259+
# > macos: use posix_spawn instead of fork
260+
# where Python subprocess options like preexec_fn are
261+
# crippled. CPython only uses posix_spawn under a pretty
262+
# strict list of conditions (see subprocess.py), and falls
263+
# back to using fork() otherwise. We'd like to simulate such
264+
# behavior with libuv, but unfortunately libuv doesn't
265+
# provide explicit API to choose such implementation detail.
266+
# Based on current (libuv 1.46) behavior, setting
267+
# UV_PROCESS_SETUID or UV_PROCESS_SETGID would reliably make
268+
# libuv fallback to use fork, so let's just use it for now.
269+
self.options.flags |= uv.UV_PROCESS_SETUID
270+
self.options.uid = uv.getuid()
271+
249272
if cwd is not None:
250273
cwd = os_fspath(cwd)
251274

uvloop/includes/uv.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from libc.stdint cimport uint16_t, uint32_t, uint64_t, int64_t
22
from posix.types cimport gid_t, uid_t
3+
from posix.unistd cimport getuid
34

45
from . cimport system
56

0 commit comments

Comments
 (0)