master end of the pseudo-terminal. For a more portable approach, use the
:mod:`pty` module. If an error occurs :exc:`OSError` is raised.
+ The returned file descriptor *fd* is :ref:`non-inheritable <fd_inheritance>`.
+
.. audit-event:: os.forkpty "" os.forkpty
.. warning::
threads, this now raises a :exc:`DeprecationWarning`. See the
longer explanation on :func:`os.fork`.
+ .. versionchanged:: next
+ The returned file descriptor is now made non-inheritable.
+
.. availability:: Unix, not WASI, not Android, not iOS.
file descriptor connected to the child's controlling terminal (and also to the
child's standard input and output).
+ The returned file descriptor *fd* is :ref:`non-inheritable <fd_inheritance>`.
+
.. warning:: On macOS the use of this function is unsafe when mixed with using
higher-level system APIs, and that includes using :mod:`urllib.request`.
+ .. versionchanged:: next
+ The returned file descriptor is now made non-inheritable.
+
.. function:: openpty()
os._exit(2)
os._exit(4)
else:
+ self.assertFalse(os.get_inheritable(master_fd))
debug("Waiting for child (%d) to finish." % pid)
# In verbose mode, we have to consume the debug output from the
# child or the child will block, causing this test to hang in the
--- /dev/null
+:func:`os.forkpty` does now make the returned file descriptor non-inheritable.
"Returns a tuple of (pid, master_fd).\n"
"Like fork(), return pid of 0 to the child process,\n"
"and pid of child to the parent process.\n"
-"To both, return fd of newly opened pseudo-terminal.");
+"To both, return fd of newly opened pseudo-terminal.\n"
+"The master_fd is non-inheritable.");
#define OS_FORKPTY_METHODDEF \
{"forkpty", (PyCFunction)os_forkpty, METH_NOARGS, os_forkpty__doc__},
#ifndef OS__EMSCRIPTEN_LOG_METHODDEF
#define OS__EMSCRIPTEN_LOG_METHODDEF
#endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */
-/*[clinic end generated code: output=b5b370c499174f85 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=47ace1528820858b input=a9049054013a1b77]*/
Like fork(), return pid of 0 to the child process,
and pid of child to the parent process.
To both, return fd of newly opened pseudo-terminal.
+The master_fd is non-inheritable.
[clinic start generated code]*/
static PyObject *
os_forkpty_impl(PyObject *module)
-/*[clinic end generated code: output=60d0a5c7512e4087 input=f1f7f4bae3966010]*/
+/*[clinic end generated code: output=60d0a5c7512e4087 input=24765e0f33275b3b]*/
{
int master_fd = -1;
pid_t pid;
} else {
/* parent: release the import lock. */
PyOS_AfterFork_Parent();
+ /* set O_CLOEXEC on master_fd */
+ if (_Py_set_inheritable(master_fd, 0, NULL) < 0) {
+ PyErr_FormatUnraisable("Exception ignored when setting master_fd "
+ "non-inheritable in forkpty()");
+ }
+
// After PyOS_AfterFork_Parent() starts the world to avoid deadlock.
if (warn_about_fork_with_threads("forkpty") < 0)
return NULL;
if (pid == -1) {
return posix_error();
}
+
return Py_BuildValue("(Ni)", PyLong_FromPid(pid), master_fd);
}
#endif /* HAVE_FORKPTY */