@@ -46,9 +46,17 @@ cdef class UVProcess(UVHandle):
46
46
# callbacks have a chance to avoid casting *something* into UVHandle.
47
47
self ._handle.data = NULL
48
48
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
+
49
57
try :
50
58
self ._init_options(args, env, cwd, start_new_session,
51
- _stdin, _stdout, _stderr)
59
+ _stdin, _stdout, _stderr, force_fork )
52
60
53
61
restore_inheritable = set ()
54
62
if pass_fds:
@@ -232,7 +240,7 @@ cdef class UVProcess(UVHandle):
232
240
return ret
233
241
234
242
cdef _init_options(self , list args, dict env, cwd, start_new_session,
235
- _stdin, _stdout, _stderr):
243
+ _stdin, _stdout, _stderr, bint force_fork ):
236
244
237
245
memset(& self .options, 0 , sizeof(uv.uv_process_options_t))
238
246
@@ -246,6 +254,21 @@ cdef class UVProcess(UVHandle):
246
254
if start_new_session:
247
255
self .options.flags |= uv.UV_PROCESS_DETACHED
248
256
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
+
249
272
if cwd is not None :
250
273
cwd = os_fspath(cwd)
251
274
0 commit comments