summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/subprocess.rst25
-rw-r--r--Lib/multiprocessing/util.py3
-rw-r--r--Lib/subprocess.py3
-rw-r--r--Lib/test/test_capi/test_misc.py6
-rw-r--r--Lib/test/test_subprocess.py22
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-06-28-23-17-22.gh-issue-121381.i2xL7P.rst2
-rw-r--r--Modules/_posixsubprocess.c7
-rw-r--r--Modules/clinic/_posixsubprocess.c.h15
8 files changed, 21 insertions, 62 deletions
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index a0ba97f..f10a808 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -1561,36 +1561,22 @@ runtime):
Module which provides function to parse and escape command lines.
-.. _disable_vfork:
.. _disable_posix_spawn:
-Disabling use of ``vfork()`` or ``posix_spawn()``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Disable use of ``posix_spawn()``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
On Linux, :mod:`subprocess` defaults to using the ``vfork()`` system call
internally when it is safe to do so rather than ``fork()``. This greatly
improves performance.
-If you ever encounter a presumed highly unusual situation where you need to
-prevent ``vfork()`` from being used by Python, you can set the
-:const:`subprocess._USE_VFORK` attribute to a false value.
-
-::
-
- subprocess._USE_VFORK = False # See CPython issue gh-NNNNNN.
-
-Setting this has no impact on use of ``posix_spawn()`` which could use
-``vfork()`` internally within its libc implementation. There is a similar
-:const:`subprocess._USE_POSIX_SPAWN` attribute if you need to prevent use of
-that.
-
::
subprocess._USE_POSIX_SPAWN = False # See CPython issue gh-NNNNNN.
-It is safe to set these to false on any Python version. They will have no
-effect on older versions when unsupported. Do not assume the attributes are
-available to read. Despite their names, a true value does not indicate that the
+It is safe to set this to false on any Python version. It will have no
+effect on older or newer versions where unsupported. Do not assume the attribute
+is available to read. Despite the name, a true value does not indicate the
corresponding function will be used, only that it may be.
Please file issues any time you have to use these private knobs with a way to
@@ -1598,4 +1584,3 @@ reproduce the issue you were seeing. Link to that issue from a comment in your
code.
.. versionadded:: 3.8 ``_USE_POSIX_SPAWN``
-.. versionadded:: 3.11 ``_USE_VFORK``
diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py
index 4f471fb..d48ef8a 100644
--- a/Lib/multiprocessing/util.py
+++ b/Lib/multiprocessing/util.py
@@ -445,8 +445,7 @@ def spawnv_passfds(path, args, passfds):
return _posixsubprocess.fork_exec(
args, [path], True, passfds, None, None,
-1, -1, -1, -1, -1, -1, errpipe_read, errpipe_write,
- False, False, -1, None, None, None, -1, None,
- subprocess._USE_VFORK)
+ False, False, -1, None, None, None, -1, None)
finally:
os.close(errpipe_read)
os.close(errpipe_write)
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index bc08878..88f0230 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -749,7 +749,6 @@ def _use_posix_spawn():
# These are primarily fail-safe knobs for negatives. A True value does not
# guarantee the given libc/syscall API will be used.
_USE_POSIX_SPAWN = _use_posix_spawn()
-_USE_VFORK = True
_HAVE_POSIX_SPAWN_CLOSEFROM = hasattr(os, 'POSIX_SPAWN_CLOSEFROM')
@@ -1902,7 +1901,7 @@ class Popen:
errpipe_read, errpipe_write,
restore_signals, start_new_session,
process_group, gid, gids, uid, umask,
- preexec_fn, _USE_VFORK)
+ preexec_fn)
self._child_created = True
finally:
# be sure the FD is closed no matter what
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index 9de97c0..5c4547d 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -120,7 +120,7 @@ class CAPITest(unittest.TestCase):
return 1
with self.assertRaisesRegex(TypeError, 'indexing'):
_posixsubprocess.fork_exec(
- 1,Z(),True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22,False)
+ 1,Z(),True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22)
# Issue #15736: overflow in _PySequence_BytesToCharpArray()
class Z(object):
def __len__(self):
@@ -128,7 +128,7 @@ class CAPITest(unittest.TestCase):
def __getitem__(self, i):
return b'x'
self.assertRaises(MemoryError, _posixsubprocess.fork_exec,
- 1,Z(),True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22,False)
+ 1,Z(),True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22)
@unittest.skipUnless(_posixsubprocess, '_posixsubprocess required for this test.')
def test_subprocess_fork_exec(self):
@@ -138,7 +138,7 @@ class CAPITest(unittest.TestCase):
# Issue #15738: crash in subprocess_fork_exec()
self.assertRaises(TypeError, _posixsubprocess.fork_exec,
- 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)
+ Z(),[b'1'],True,(1, 2),5,6,7,8,9,10,11,12,13,14,True,True,17,False,19,20,21,22)
@unittest.skipIf(MISSING_C_DOCSTRINGS,
"Signature information for builtins requires docstrings")
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 9412a2d..f065b9c 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -3278,7 +3278,7 @@ class POSIXProcessTestCase(BaseTestCase):
1, 2, 3, 4,
True, True, 0,
None, None, None, -1,
- None, True)
+ None)
self.assertIn('fds_to_keep', str(c.exception))
finally:
if not gc_enabled:
@@ -3415,25 +3415,6 @@ class POSIXProcessTestCase(BaseTestCase):
@unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"),
"vfork() not enabled by configure.")
- @mock.patch("subprocess._fork_exec")
- @mock.patch("subprocess._USE_POSIX_SPAWN", new=False)
- def test__use_vfork(self, mock_fork_exec):
- self.assertTrue(subprocess._USE_VFORK) # The default value regardless.
- mock_fork_exec.side_effect = RuntimeError("just testing args")
- with self.assertRaises(RuntimeError):
- subprocess.run([sys.executable, "-c", "pass"])
- mock_fork_exec.assert_called_once()
- # NOTE: These assertions are *ugly* as they require the last arg
- # to remain the have_vfork boolean. We really need to refactor away
- # from the giant "wall of args" internal C extension API.
- self.assertTrue(mock_fork_exec.call_args.args[-1])
- with mock.patch.object(subprocess, '_USE_VFORK', False):
- with self.assertRaises(RuntimeError):
- subprocess.run([sys.executable, "-c", "pass"])
- self.assertFalse(mock_fork_exec.call_args_list[-1].args[-1])
-
- @unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"),
- "vfork() not enabled by configure.")
@unittest.skipIf(sys.platform != "linux", "Linux only, requires strace.")
@mock.patch("subprocess._USE_POSIX_SPAWN", new=False)
def test_vfork_used_when_expected(self):
@@ -3478,7 +3459,6 @@ class POSIXProcessTestCase(BaseTestCase):
# Test that each individual thing that would disable the use of vfork
# actually disables it.
for sub_name, preamble, sp_kwarg, expect_permission_error in (
- ("!use_vfork", "subprocess._USE_VFORK = False", "", False),
("preexec", "", "preexec_fn=lambda: None", False),
("setgid", "", f"group={os.getgid()}", True),
("setuid", "", f"user={os.getuid()}", True),
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-28-23-17-22.gh-issue-121381.i2xL7P.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-28-23-17-22.gh-issue-121381.i2xL7P.rst
new file mode 100644
index 0000000..3a02145
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-06-28-23-17-22.gh-issue-121381.i2xL7P.rst
@@ -0,0 +1,2 @@
+Remove ``subprocess._USE_VFORK`` escape hatch code and documentation.
+It was added just in case, and doesn't have any known cases that require it.
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
index daec4ad..ad6d7ce 100644
--- a/Modules/_posixsubprocess.c
+++ b/Modules/_posixsubprocess.c
@@ -977,7 +977,6 @@ _posixsubprocess.fork_exec as subprocess_fork_exec
uid as uid_object: object
child_umask: int
preexec_fn: object
- allow_vfork: bool
/
Spawn a fresh new child process.
@@ -1014,8 +1013,8 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
pid_t pgid_to_set, PyObject *gid_object,
PyObject *extra_groups_packed,
PyObject *uid_object, int child_umask,
- PyObject *preexec_fn, int allow_vfork)
-/*[clinic end generated code: output=7ee4f6ee5cf22b5b input=51757287ef266ffa]*/
+ PyObject *preexec_fn)
+/*[clinic end generated code: output=288464dc56e373c7 input=f311c3bcb5dd55c8]*/
{
PyObject *converted_args = NULL, *fast_args = NULL;
PyObject *preexec_fn_args_tuple = NULL;
@@ -1218,7 +1217,7 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
#ifdef VFORK_USABLE
/* Use vfork() only if it's safe. See the comment above child_exec(). */
sigset_t old_sigs;
- if (preexec_fn == Py_None && allow_vfork &&
+ if (preexec_fn == Py_None &&
uid == (uid_t)-1 && gid == (gid_t)-1 && extra_group_size < 0) {
/* Block all signals to ensure that no signal handlers are run in the
* child process while it shares memory with us. Note that signals
diff --git a/Modules/clinic/_posixsubprocess.c.h b/Modules/clinic/_posixsubprocess.c.h
index dd7644d..d52629c 100644
--- a/Modules/clinic/_posixsubprocess.c.h
+++ b/Modules/clinic/_posixsubprocess.c.h
@@ -9,7 +9,7 @@ PyDoc_STRVAR(subprocess_fork_exec__doc__,
" env, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite,\n"
" errpipe_read, errpipe_write, restore_signals, call_setsid,\n"
" pgid_to_set, gid, extra_groups, uid, child_umask, preexec_fn,\n"
-" allow_vfork, /)\n"
+" /)\n"
"--\n"
"\n"
"Spawn a fresh new child process.\n"
@@ -48,7 +48,7 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
pid_t pgid_to_set, PyObject *gid_object,
PyObject *extra_groups_packed,
PyObject *uid_object, int child_umask,
- PyObject *preexec_fn, int allow_vfork);
+ PyObject *preexec_fn);
static PyObject *
subprocess_fork_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
@@ -76,9 +76,8 @@ subprocess_fork_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
PyObject *uid_object;
int child_umask;
PyObject *preexec_fn;
- int allow_vfork;
- if (!_PyArg_CheckPositional("fork_exec", nargs, 23, 23)) {
+ if (!_PyArg_CheckPositional("fork_exec", nargs, 22, 22)) {
goto exit;
}
process_args = args[0];
@@ -146,13 +145,9 @@ subprocess_fork_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
goto exit;
}
preexec_fn = args[21];
- allow_vfork = PyObject_IsTrue(args[22]);
- if (allow_vfork < 0) {
- goto exit;
- }
- return_value = subprocess_fork_exec_impl(module, process_args, executable_list, close_fds, py_fds_to_keep, cwd_obj, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, restore_signals, call_setsid, pgid_to_set, gid_object, extra_groups_packed, uid_object, child_umask, preexec_fn, allow_vfork);
+ return_value = subprocess_fork_exec_impl(module, process_args, executable_list, close_fds, py_fds_to_keep, cwd_obj, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, restore_signals, call_setsid, pgid_to_set, gid_object, extra_groups_packed, uid_object, child_umask, preexec_fn);
exit:
return return_value;
}
-/*[clinic end generated code: output=48555f5965a871be input=a9049054013a1b77]*/
+/*[clinic end generated code: output=942bc2748a9c2785 input=a9049054013a1b77]*/