mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
gh-77046: os.pipe() sets _O_NOINHERIT flag on fds (#113817)
On Windows, set _O_NOINHERIT flag on file descriptors created by os.pipe() and io.WindowsConsoleIO. Add test_pipe_spawnl() to test_os. Co-authored-by: Zackery Spytz <zspytz@gmail.com>
This commit is contained in:
parent
e82b096335
commit
1d75fa43a2
5 changed files with 68 additions and 6 deletions
|
@ -75,10 +75,14 @@ File Operations
|
||||||
.. function:: open_osfhandle(handle, flags)
|
.. function:: open_osfhandle(handle, flags)
|
||||||
|
|
||||||
Create a C runtime file descriptor from the file handle *handle*. The *flags*
|
Create a C runtime file descriptor from the file handle *handle*. The *flags*
|
||||||
parameter should be a bitwise OR of :const:`os.O_APPEND`, :const:`os.O_RDONLY`,
|
parameter should be a bitwise OR of :const:`os.O_APPEND`,
|
||||||
and :const:`os.O_TEXT`. The returned file descriptor may be used as a parameter
|
:const:`os.O_RDONLY`, :const:`os.O_TEXT` and :const:`os.O_NOINHERIT`.
|
||||||
|
The returned file descriptor may be used as a parameter
|
||||||
to :func:`os.fdopen` to create a file object.
|
to :func:`os.fdopen` to create a file object.
|
||||||
|
|
||||||
|
The file descriptor is inheritable by default. Pass :const:`os.O_NOINHERIT`
|
||||||
|
flag to make it non inheritable.
|
||||||
|
|
||||||
.. audit-event:: msvcrt.open_osfhandle handle,flags msvcrt.open_osfhandle
|
.. audit-event:: msvcrt.open_osfhandle handle,flags msvcrt.open_osfhandle
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4485,6 +4485,61 @@ class FDInheritanceTests(unittest.TestCase):
|
||||||
self.assertEqual(os.get_inheritable(master_fd), False)
|
self.assertEqual(os.get_inheritable(master_fd), False)
|
||||||
self.assertEqual(os.get_inheritable(slave_fd), False)
|
self.assertEqual(os.get_inheritable(slave_fd), False)
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(os, 'spawnl'), "need os.openpty()")
|
||||||
|
def test_pipe_spawnl(self):
|
||||||
|
# gh-77046: On Windows, os.pipe() file descriptors must be created with
|
||||||
|
# _O_NOINHERIT to make them non-inheritable. UCRT has no public API to
|
||||||
|
# get (_osfile(fd) & _O_NOINHERIT), so use a functional test.
|
||||||
|
#
|
||||||
|
# Make sure that fd is not inherited by a child process created by
|
||||||
|
# os.spawnl(): get_osfhandle() and dup() must fail with EBADF.
|
||||||
|
|
||||||
|
fd, fd2 = os.pipe()
|
||||||
|
self.addCleanup(os.close, fd)
|
||||||
|
self.addCleanup(os.close, fd2)
|
||||||
|
|
||||||
|
code = textwrap.dedent(f"""
|
||||||
|
import errno
|
||||||
|
import os
|
||||||
|
import test.support
|
||||||
|
try:
|
||||||
|
import msvcrt
|
||||||
|
except ImportError:
|
||||||
|
msvcrt = None
|
||||||
|
|
||||||
|
fd = {fd}
|
||||||
|
|
||||||
|
with test.support.SuppressCrashReport():
|
||||||
|
if msvcrt is not None:
|
||||||
|
try:
|
||||||
|
handle = msvcrt.get_osfhandle(fd)
|
||||||
|
except OSError as exc:
|
||||||
|
if exc.errno != errno.EBADF:
|
||||||
|
raise
|
||||||
|
# get_osfhandle(fd) failed with EBADF as expected
|
||||||
|
else:
|
||||||
|
raise Exception("get_osfhandle() must fail")
|
||||||
|
|
||||||
|
try:
|
||||||
|
fd3 = os.dup(fd)
|
||||||
|
except OSError as exc:
|
||||||
|
if exc.errno != errno.EBADF:
|
||||||
|
raise
|
||||||
|
# os.dup(fd) failed with EBADF as expected
|
||||||
|
else:
|
||||||
|
os.close(fd3)
|
||||||
|
raise Exception("dup must fail")
|
||||||
|
""")
|
||||||
|
|
||||||
|
filename = os_helper.TESTFN
|
||||||
|
self.addCleanup(os_helper.unlink, os_helper.TESTFN)
|
||||||
|
with open(filename, "w") as fp:
|
||||||
|
print(code, file=fp, end="")
|
||||||
|
|
||||||
|
cmd = [sys.executable, filename]
|
||||||
|
exitcode = os.spawnl(os.P_WAIT, cmd[0], *cmd)
|
||||||
|
self.assertEqual(exitcode, 0)
|
||||||
|
|
||||||
|
|
||||||
class PathTConverterTests(unittest.TestCase):
|
class PathTConverterTests(unittest.TestCase):
|
||||||
# tuples of (function name, allows fd arguments, additional arguments to
|
# tuples of (function name, allows fd arguments, additional arguments to
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
On Windows, file descriptors wrapping Windows handles are now created non
|
||||||
|
inheritable by default (:pep:`446`). Patch by Zackery Spytz and Victor
|
||||||
|
Stinner.
|
|
@ -391,9 +391,9 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->writable)
|
if (self->writable)
|
||||||
self->fd = _Py_open_osfhandle_noraise(handle, _O_WRONLY | _O_BINARY);
|
self->fd = _Py_open_osfhandle_noraise(handle, _O_WRONLY | _O_BINARY | _O_NOINHERIT);
|
||||||
else
|
else
|
||||||
self->fd = _Py_open_osfhandle_noraise(handle, _O_RDONLY | _O_BINARY);
|
self->fd = _Py_open_osfhandle_noraise(handle, _O_RDONLY | _O_BINARY | _O_NOINHERIT);
|
||||||
if (self->fd < 0) {
|
if (self->fd < 0) {
|
||||||
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
|
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
|
||||||
CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
|
|
|
@ -11578,8 +11578,8 @@ os_pipe_impl(PyObject *module)
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
ok = CreatePipe(&read, &write, &attr, 0);
|
ok = CreatePipe(&read, &write, &attr, 0);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
fds[0] = _Py_open_osfhandle_noraise(read, _O_RDONLY);
|
fds[0] = _Py_open_osfhandle_noraise(read, _O_RDONLY | _O_NOINHERIT);
|
||||||
fds[1] = _Py_open_osfhandle_noraise(write, _O_WRONLY);
|
fds[1] = _Py_open_osfhandle_noraise(write, _O_WRONLY | _O_NOINHERIT);
|
||||||
if (fds[0] == -1 || fds[1] == -1) {
|
if (fds[0] == -1 || fds[1] == -1) {
|
||||||
CloseHandle(read);
|
CloseHandle(read);
|
||||||
CloseHandle(write);
|
CloseHandle(write);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue