@@ -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 not (
51+ preexec_fn is None
52+ and 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
0 commit comments