Skip to content

Commit a9344cd

Browse files
authored
gh-121381 Remove subprocess._USE_VFORK escape hatch (#121383)
This flag was added as an escape hatch in gh-91401 and backported to Python 3.10. The flag broke at some point between its addition and now. As there is currently no publicly known environments that require this, remove it rather than work on fixing it. This leaves the flag in the subprocess module to not break code which may have used / checked the flag itself. discussion: https://discuss.python.org/t/subprocess-use-vfork-escape-hatch-broken-fix-or-remove/56915/2
1 parent 82db572 commit a9344cd

File tree

8 files changed

+21
-62
lines changed

8 files changed

+21
-62
lines changed

Doc/library/subprocess.rst

+5-20
Original file line numberDiff line numberDiff line change
@@ -1561,41 +1561,26 @@ runtime):
15611561
Module which provides function to parse and escape command lines.
15621562

15631563

1564-
.. _disable_vfork:
15651564
.. _disable_posix_spawn:
15661565

1567-
Disabling use of ``vfork()`` or ``posix_spawn()``
1568-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1566+
Disable use of ``posix_spawn()``
1567+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15691568

15701569
On Linux, :mod:`subprocess` defaults to using the ``vfork()`` system call
15711570
internally when it is safe to do so rather than ``fork()``. This greatly
15721571
improves performance.
15731572

1574-
If you ever encounter a presumed highly unusual situation where you need to
1575-
prevent ``vfork()`` from being used by Python, you can set the
1576-
:const:`subprocess._USE_VFORK` attribute to a false value.
1577-
1578-
::
1579-
1580-
subprocess._USE_VFORK = False # See CPython issue gh-NNNNNN.
1581-
1582-
Setting this has no impact on use of ``posix_spawn()`` which could use
1583-
``vfork()`` internally within its libc implementation. There is a similar
1584-
:const:`subprocess._USE_POSIX_SPAWN` attribute if you need to prevent use of
1585-
that.
1586-
15871573
::
15881574

15891575
subprocess._USE_POSIX_SPAWN = False # See CPython issue gh-NNNNNN.
15901576

1591-
It is safe to set these to false on any Python version. They will have no
1592-
effect on older versions when unsupported. Do not assume the attributes are
1593-
available to read. Despite their names, a true value does not indicate that the
1577+
It is safe to set this to false on any Python version. It will have no
1578+
effect on older or newer versions where unsupported. Do not assume the attribute
1579+
is available to read. Despite the name, a true value does not indicate the
15941580
corresponding function will be used, only that it may be.
15951581

15961582
Please file issues any time you have to use these private knobs with a way to
15971583
reproduce the issue you were seeing. Link to that issue from a comment in your
15981584
code.
15991585

16001586
.. versionadded:: 3.8 ``_USE_POSIX_SPAWN``
1601-
.. versionadded:: 3.11 ``_USE_VFORK``

Lib/multiprocessing/util.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,7 @@ def spawnv_passfds(path, args, passfds):
445445
return _posixsubprocess.fork_exec(
446446
args, [path], True, passfds, None, None,
447447
-1, -1, -1, -1, -1, -1, errpipe_read, errpipe_write,
448-
False, False, -1, None, None, None, -1, None,
449-
subprocess._USE_VFORK)
448+
False, False, -1, None, None, None, -1, None)
450449
finally:
451450
os.close(errpipe_read)
452451
os.close(errpipe_write)

Lib/subprocess.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,6 @@ def _use_posix_spawn():
749749
# These are primarily fail-safe knobs for negatives. A True value does not
750750
# guarantee the given libc/syscall API will be used.
751751
_USE_POSIX_SPAWN = _use_posix_spawn()
752-
_USE_VFORK = True
753752
_HAVE_POSIX_SPAWN_CLOSEFROM = hasattr(os, 'POSIX_SPAWN_CLOSEFROM')
754753

755754

@@ -1902,7 +1901,7 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
19021901
errpipe_read, errpipe_write,
19031902
restore_signals, start_new_session,
19041903
process_group, gid, gids, uid, umask,
1905-
preexec_fn, _USE_VFORK)
1904+
preexec_fn)
19061905
self._child_created = True
19071906
finally:
19081907
# be sure the FD is closed no matter what

Lib/test/test_capi/test_misc.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,15 @@ def __len__(self):
120120
return 1
121121
with self.assertRaisesRegex(TypeError, 'indexing'):
122122
_posixsubprocess.fork_exec(
123-
1,Z(),True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22,False)
123+
1,Z(),True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22)
124124
# Issue #15736: overflow in _PySequence_BytesToCharpArray()
125125
class Z(object):
126126
def __len__(self):
127127
return sys.maxsize
128128
def __getitem__(self, i):
129129
return b'x'
130130
self.assertRaises(MemoryError, _posixsubprocess.fork_exec,
131-
1,Z(),True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22,False)
131+
1,Z(),True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22)
132132

133133
@unittest.skipUnless(_posixsubprocess, '_posixsubprocess required for this test.')
134134
def test_subprocess_fork_exec(self):
@@ -138,7 +138,7 @@ def __len__(self):
138138

139139
# Issue #15738: crash in subprocess_fork_exec()
140140
self.assertRaises(TypeError, _posixsubprocess.fork_exec,
141-
Z(),[b'1'],True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22,False)
141+
Z(),[b'1'],True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22)
142142

143143
@unittest.skipIf(MISSING_C_DOCSTRINGS,
144144
"Signature information for builtins requires docstrings")

Lib/test/test_subprocess.py

+1-21
Original file line numberDiff line numberDiff line change
@@ -3278,7 +3278,7 @@ def __int__(self):
32783278
1, 2, 3, 4,
32793279
True, True, 0,
32803280
None, None, None, -1,
3281-
None, True)
3281+
None)
32823282
self.assertIn('fds_to_keep', str(c.exception))
32833283
finally:
32843284
if not gc_enabled:
@@ -3413,25 +3413,6 @@ def __del__(self):
34133413
self.assertEqual(out.strip(), b"OK")
34143414
self.assertIn(b"preexec_fn not supported at interpreter shutdown", err)
34153415

3416-
@unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"),
3417-
"vfork() not enabled by configure.")
3418-
@mock.patch("subprocess._fork_exec")
3419-
@mock.patch("subprocess._USE_POSIX_SPAWN", new=False)
3420-
def test__use_vfork(self, mock_fork_exec):
3421-
self.assertTrue(subprocess._USE_VFORK) # The default value regardless.
3422-
mock_fork_exec.side_effect = RuntimeError("just testing args")
3423-
with self.assertRaises(RuntimeError):
3424-
subprocess.run([sys.executable, "-c", "pass"])
3425-
mock_fork_exec.assert_called_once()
3426-
# NOTE: These assertions are *ugly* as they require the last arg
3427-
# to remain the have_vfork boolean. We really need to refactor away
3428-
# from the giant "wall of args" internal C extension API.
3429-
self.assertTrue(mock_fork_exec.call_args.args[-1])
3430-
with mock.patch.object(subprocess, '_USE_VFORK', False):
3431-
with self.assertRaises(RuntimeError):
3432-
subprocess.run([sys.executable, "-c", "pass"])
3433-
self.assertFalse(mock_fork_exec.call_args_list[-1].args[-1])
3434-
34353416
@unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"),
34363417
"vfork() not enabled by configure.")
34373418
@unittest.skipIf(sys.platform != "linux", "Linux only, requires strace.")
@@ -3478,7 +3459,6 @@ def test_vfork_used_when_expected(self):
34783459
# Test that each individual thing that would disable the use of vfork
34793460
# actually disables it.
34803461
for sub_name, preamble, sp_kwarg, expect_permission_error in (
3481-
("!use_vfork", "subprocess._USE_VFORK = False", "", False),
34823462
("preexec", "", "preexec_fn=lambda: None", False),
34833463
("setgid", "", f"group={os.getgid()}", True),
34843464
("setuid", "", f"user={os.getuid()}", True),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Remove ``subprocess._USE_VFORK`` escape hatch code and documentation.
2+
It was added just in case, and doesn't have any known cases that require it.

Modules/_posixsubprocess.c

+3-4
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,6 @@ _posixsubprocess.fork_exec as subprocess_fork_exec
977977
uid as uid_object: object
978978
child_umask: int
979979
preexec_fn: object
980-
allow_vfork: bool
981980
/
982981
983982
Spawn a fresh new child process.
@@ -1014,8 +1013,8 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
10141013
pid_t pgid_to_set, PyObject *gid_object,
10151014
PyObject *extra_groups_packed,
10161015
PyObject *uid_object, int child_umask,
1017-
PyObject *preexec_fn, int allow_vfork)
1018-
/*[clinic end generated code: output=7ee4f6ee5cf22b5b input=51757287ef266ffa]*/
1016+
PyObject *preexec_fn)
1017+
/*[clinic end generated code: output=288464dc56e373c7 input=f311c3bcb5dd55c8]*/
10191018
{
10201019
PyObject *converted_args = NULL, *fast_args = NULL;
10211020
PyObject *preexec_fn_args_tuple = NULL;
@@ -1218,7 +1217,7 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
12181217
#ifdef VFORK_USABLE
12191218
/* Use vfork() only if it's safe. See the comment above child_exec(). */
12201219
sigset_t old_sigs;
1221-
if (preexec_fn == Py_None && allow_vfork &&
1220+
if (preexec_fn == Py_None &&
12221221
uid == (uid_t)-1 && gid == (gid_t)-1 && extra_group_size < 0) {
12231222
/* Block all signals to ensure that no signal handlers are run in the
12241223
* child process while it shares memory with us. Note that signals

Modules/clinic/_posixsubprocess.c.h

+5-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)