cpython: ef889c3d5dc6 (original) (raw)
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -979,6 +979,8 @@ are always available. They are listed h
:mod:os.open
as opener results in functionality similar to passing
None
).
- The newly created file is :ref:
non-inheritable <fd_inheritance>
. + The following example uses the :ref:dir_fd <dir_fd>
parameter of the :func:os.open
function to open a file relative to a given directory::
@@ -992,10 +994,6 @@ are always available. They are listed h ... >>> os.close(dir_fd) # don't leak a file descriptor
- .. versionchanged:: 3.3
The *opener* parameter was added.[](#l1.17)
The ``'x'`` mode was added.[](#l1.18)
-
The type of :term:file object
returned by the :func:open
function
depends on the mode. When :func:open
is used to open a file in a text
mode ('w'
, 'r'
, 'wt'
, 'rt'
, etc.), it returns a subclass of
@@ -1022,10 +1020,15 @@ are always available. They are listed h
and :mod:shutil
.
.. versionchanged:: 3.3
The *opener* parameter was added.[](#l1.27)
The ``'x'`` mode was added.[](#l1.28) :exc:`IOError` used to be raised, it is now an alias of :exc:`OSError`.[](#l1.29) :exc:`FileExistsError` is now raised if the file opened in exclusive[](#l1.30) creation mode (``'x'``) already exists.[](#l1.31)
+ .. XXX works for bytes too, but should it? .. function:: ord(c)
--- a/Doc/library/io.rst
+++ b/Doc/library/io.rst
@@ -522,6 +522,8 @@ Raw File I/O
:mod:os.open
as opener results in functionality similar to passing
None
).
- The newly created file is :ref:
non-inheritable <fd_inheritance>
. + See the :func:open
built-in function for examples on using the opener parameter.
@@ -529,6 +531,9 @@ Raw File I/O
The opener parameter was added.
The 'x'
mode was added.
+
In addition to the attributes and methods from :class:IOBase
and
:class:RawIOBase
, :class:FileIO
provides the following data
attributes:
--- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -685,17 +685,30 @@ as internal buffering of data. .. function:: dup(fd)
- Return a duplicate of file descriptor fd. The new file descriptor is
- :ref:
non-inheritable <fd_inheritance>
. + - On Windows, when duplicating a standard stream (0: stdin, 1: stdout,
- 2: stderr), the new file descriptor is :ref:`inheritable
- `. Availability: Unix, Windows.
- -.. function:: dup2(fd, fd2)
+ + +.. function:: dup2(fd, fd2, inheritable=True) Duplicate file descriptor fd to fd2, closing the latter first if necessary.
- The file descriptor fd2 is :ref:
inheritable <fd_inheritance>
by default, - or non-inheritable if inheritable is
False
. Availability: Unix, Windows. - .. versionchanged:: 3.4
Add the optional *inheritable* parameter.[](#l3.32)
+ .. function:: fchmod(fd, mode) @@ -848,6 +861,7 @@ as internal buffering of data. Open the file file and set various flags according to flags and possibly its mode according to mode. When computing mode, the current umask value is first masked out. Return the file descriptor for the newly opened file.
- The new file descriptor is :ref:
non-inheritable <fd_inheritance>
. For a description of the flag and mode values, see the C run-time documentation; flag constants (like :const:O_RDONLY
and :const:O_WRONLY
) are defined in @@ -859,6 +873,9 @@ as internal buffering of data. Availability: Unix, Windows. - .. versionchanged:: 3.4
The new file descriptor is now non-inheritable.[](#l3.50)
+ .. note:: This function is intended for low-level I/O. For normal usage, use the @@ -933,20 +950,28 @@ or `the MSDN <http://msdn.microsoft.com/[](#l3.55) .. index:: module: pty
- Open a new pseudo-terminal pair. Return a pair of file descriptors ``(master,
- slave)`` for the pty and the tty, respectively. For a (slightly) more portable
- approach, use the :mod:
pty
module.
- Open a new pseudo-terminal pair. Return a pair of file descriptors
(master, slave)
for the pty and the tty, respectively. The new file- descriptors are :ref:
non-inheritable <fd_inheritance>
. For a (slightly) more - portable approach, use the :mod:
pty
module. Availability: some flavors of Unix. - .. versionchanged:: 3.4
The new file descriptors are now non-inheritable.[](#l3.70)
- Create a pipe. Return a pair of file descriptors
(r, w)
usable for reading - and writing, respectively.
- Create a pipe. Return a pair of file descriptors
(r, w)
usable for - reading and writing, respectively. The new file descriptor are
- :ref:
non-inheritable <fd_inheritance>
. Availability: Unix, Windows. - .. versionchanged:: 3.4
The new file descriptors are now non-inheritable.[](#l3.84)
+
.. function:: pipe2(flags)
@@ -1178,6 +1203,50 @@ Querying the size of a terminal
Height of the terminal window in characters.
+.. _fd_inheritance:
+
+Inheritance of File Descriptors
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A file descriptor has a inheritable flag which indicates if the file descriptor
+can be inherited or not in child processes. Since Python 3.4, file descriptors
+created by Python are non-inheritable by default.
+
+On UNIX, non-inheritable file descriptors are closed in child processes at the
+execution of a new program, other file descriptors are inherited.
+
+On Windows, non-inheritable handles and file descriptors are closed in child
+processes, except standard streams (file descriptors 0, 1 and 2: stdin, stdout
+and stderr) which are always inherited. Using :func:os.spawn*
functions,
+all inheritable handles and all inheritable file descriptors are inherited.
+Using the :mod:subprocess
module, all file descriptors except standard
+streams are closed, inheritable handles are only inherited if the close_fds
+parameter is False
.
+
+.. versionadded:: 3.4
+
+.. function:: get_inheritable(fd)
+
- Get the
inheritable flag <fd_inheritance>
_ of the specified file - descriptor. Return a :class:
bool
. +
+.. function:: set_inheritable(fd, inheritable) +
+.. function:: get_handle_inheritable(handle) +
- Get the
inheritable flag <fd_inheritance>
_ of the specified handle. Return a :class:bool
. + - Availability: Windows. +
+.. function:: set_handle_inheritable(handle, inheritable) +
+ .. _os-file-dir: Files and Directories
--- a/Doc/library/select.rst
+++ b/Doc/library/select.rst
@@ -37,8 +37,13 @@ The module defines the following:
increases this value, :c:func:devpoll
may return an
incomplete list of active file descriptors.
- The new file descriptor is :ref:
non-inheritable <fd_inheritance>
. + .. versionadded:: 3.3 - .. versionchanged:: 3.4
The new file descriptor is now non-inheritable.[](#l4.12)
+
.. function:: epoll(sizehint=-1, flags=0)
(Only supported on Linux 2.5.44 and newer.) Return an edge polling object,
@@ -49,11 +54,14 @@ The module defines the following:
:ref:epoll-objects
below for the methods supported by epolling objects.
They also support the :keyword:with
statement.
- The new file descriptor is :ref:
non-inheritable <fd_inheritance>
. + .. versionchanged:: 3.3 Added the flags parameter. .. versionchanged:: 3.4 Support for the :keyword:with
statement was added. The new file descriptor is now non-inheritable.[](#l4.28)
.. function:: poll()
@@ -69,6 +77,11 @@ The module defines the following:
(Only supported on BSD.) Returns a kernel queue object; see section
:ref:kqueue-objects
below for the methods supported by kqueue objects.
- The new file descriptor is :ref:
non-inheritable <fd_inheritance>
. + - .. versionchanged:: 3.4
The new file descriptor is now non-inheritable.[](#l4.39)
+ .. function:: kevent(ident, filter=KQ_FILTER_READ, flags=KQ_EV_ADD, fflags=0, data=0, udata=0)
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -460,7 +460,7 @@ The module :mod:socket
exports the fol
'udp'
, otherwise any protocol will match.
-.. function:: socket([family[, type[, proto]]])
+.. function:: socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
Create a new socket using the given address family, socket type and protocol
number. The address family should be :const:AF_INET
(the default),
@@ -471,12 +471,18 @@ The module :mod:socket
exports the fol
case where the address family is :const:AF_CAN
the protocol should be one
of :const:CAN_RAW
or :const:CAN_BCM
.
- The newly created socket is :ref:
non-inheritable <fd_inheritance>
. + .. versionchanged:: 3.3 The AF_CAN family was added. The AF_RDS family was added.
+
.. function:: socketpair([family[, type[, proto]]])
@@ -486,12 +492,17 @@ The module :mod:socket
exports the fol
if defined on the platform; otherwise, the default is :const:AF_INET
.
Availability: Unix.
- The newly created sockets are :ref:
non-inheritable <fd_inheritance>
. + .. versionchanged:: 3.2 The returned socket objects now support the whole socket API, rather than a subset. - .. versionchanged:: 3.4
The sockets are now non-inheritable.[](#l5.44)
-.. function:: fromfd(fd, family, type[, proto])
+
+.. function:: fromfd(fd, family, type, proto=0)
Duplicate the file descriptor fd (an integer as returned by a file object's
:meth:fileno
method) and build a socket object from the result. Address
@@ -502,6 +513,11 @@ The module :mod:socket
exports the fol
a socket passed to a program as standard input or output (such as a server
started by the Unix inet daemon). The socket is assumed to be in blocking mode.
- The newly created socket is :ref:
non-inheritable <fd_inheritance>
. + - .. versionchanged:: 3.4
The socket is now non-inheritable.[](#l5.59)
+ .. function:: ntohl(x) @@ -730,6 +746,11 @@ correspond to Unix system calls applicab new socket object usable to send and receive data on the connection, and address is the address bound to the socket on the other end of the connection.
- The newly created socket is :ref:
non-inheritable <fd_inheritance>
. + - .. versionchanged:: 3.4
The socket is now non-inheritable.[](#l5.71)
+ .. method:: socket.bind(address) @@ -775,6 +796,16 @@ correspond to Unix system calls applicab .. versionadded:: 3.2 +.. method:: socket.dup() +
- Duplicate the socket. +
- The newly created socket is :ref:
non-inheritable <fd_inheritance>
. + - .. versionchanged:: 3.4
The socket is now non-inheritable.[](#l5.87)
+ + .. method:: socket.fileno() Return the socket's file descriptor (a small integer). This is useful with @@ -785,6 +816,15 @@ correspond to Unix system calls applicab this limitation. +.. method:: socket.get_inheritable() +
- Get the :ref:
inheritable flag <fd_inheritance>
of the socket's file - descriptor or socket's handle:
True
if the socket can be inherited in - child processes,
False
if it cannot. + - .. versionadded:: 3.4 +
+ .. method:: socket.getpeername() Return the remote address to which the socket is connected. This is useful to @@ -1068,6 +1108,14 @@ correspond to Unix system calls applicab .. versionadded:: 3.3 +.. method:: socket.set_inheritable(inheritable) +
- Set the :ref:
inheritable flag <fd_inheritance>
of the socket's file - descriptor or socket's handle. +
- .. versionadded:: 3.4 +
+ .. method:: socket.setblocking(flag) Set blocking or non-blocking mode of the socket: if flag is false, the
--- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -96,6 +96,7 @@ New built-in features:
- :ref:
PEP 442: Safe object finalization <pep-442>
. - :ref:
PEP 445: Configurable memory allocators <pep-445>
. +* :ref:PEP 446: Make newly created file descriptors non-inheritable <pep-446>
. Implementation improvements: @@ -118,6 +119,19 @@ Security improvements: Please read on for a comprehensive list of user-facing changes. +.. pep-446: + +PEP 446: Make newly created file descriptors non-inheritable +============================================================ + +The :pep:446
makes newly created file descriptorsnon-inheritable[](#l6.20) +<fd_inheritance>
. New functions and methods: + +* :func:os.get_inheritable
, :func:os.set_inheritable
+* :func:os.get_handle_inheritable
, :func:os.set_handle_inheritable
+* :meth:socket.socket.get_inheritable
, :meth:socket.socket.set_inheritable
+ + .. pep-445: PEP 445: Add new APIs to customize Python memory allocators @@ -267,6 +281,16 @@ Also, except when using the old fork s will no longer inherit unneeded handles/file descriptors from their parents. +os +-- + +New functions to get and set theinheritable flag <fd_inheritance>
of a file +descriptors or a Windows handle: + +* :func:os.get_inheritable
, :func:os.set_inheritable
+* :func:os.get_handle_inheritable
, :func:os.set_handle_inheritable
+ + poplib ------ @@ -288,6 +312,15 @@ try/except statement by code that only c (:issue:2118
). +socket +------ + +Socket objects have new methods to get or set theirinheritable flag[](#l6.55) +<fd_inheritance>
_: + +* :meth:socket.socket.get_inheritable
, :meth:socket.socket.set_inheritable
+ + ssl ---
--- a/Include/fileutils.h +++ b/Include/fileutils.h @@ -27,11 +27,19 @@ PyAPI_FUNC(int) _Py_stat( struct stat *statbuf); #endif +PyAPI_FUNC(int) _Py_open(
+ PyAPI_FUNC(FILE *) _Py_wfopen( const wchar_t *path, const wchar_t mode); PyAPI_FUNC(FILE) _Py_fopen(
+ +PyAPI_FUNC(FILE*) _Py_fopen_obj( PyObject *path, const char mode); @@ -53,6 +61,13 @@ PyAPI_FUNC(wchar_t) _Py_wgetcwd( wchar_t *buf, size_t size); +PyAPI_FUNC(int) _Py_get_inheritable(int fd); + +PyAPI_FUNC(int) _Py_set_inheritable(int fd, int inheritable,
int *atomic_flag_works);[](#l7.30)
+ +PyAPI_FUNC(int) _Py_dup(int fd); + #ifdef __cplusplus } #endif
--- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -129,6 +129,8 @@ def open(file, mode="r", buffering=-1, e be kept open when the file is closed. This does not work when a file name is given and must be True in that case.
+ A custom opener can be used by passing a callable as opener. The underlying file descriptor for the file object is then obtained by calling opener with (file, flags). opener must return an open file
--- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -509,7 +509,7 @@ if sys.platform != 'win32': c1 = Connection(s1.detach()) c2 = Connection(s2.detach()) else:
fd1, fd2 = util.pipe()[](#l9.7)
fd1, fd2 = os.pipe()[](#l9.8) c1 = Connection(fd1, writable=False)[](#l9.9) c2 = Connection(fd2, readable=False)[](#l9.10)
@@ -536,7 +536,9 @@ else: _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE, _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE | _winapi.PIPE_WAIT,
1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL[](#l9.16)
1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER,[](#l9.17)
# default security descriptor: the handle cannot be inherited[](#l9.18)
_winapi.NULL[](#l9.19) )[](#l9.20) h2 = _winapi.CreateFile([](#l9.21) address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING,[](#l9.22)
--- a/Lib/multiprocessing/forkserver.py +++ b/Lib/multiprocessing/forkserver.py @@ -60,8 +60,8 @@ def connect_to_new_process(fds): raise ValueError('too many fds') with socket.socket(socket.AF_UNIX) as client: client.connect(_forkserver_address)
parent_r, child_w = util.pipe()[](#l10.7)
child_r, parent_w = util.pipe()[](#l10.8)
parent_r, child_w = os.pipe()[](#l10.9)
child_r, parent_w = os.pipe()[](#l10.10) allfds = [child_r, child_w, _forkserver_alive_fd,[](#l10.11) semaphore_tracker._semaphore_tracker_fd][](#l10.12) allfds += fds[](#l10.13)
--- a/Lib/multiprocessing/popen_fork.py +++ b/Lib/multiprocessing/popen_fork.py @@ -66,7 +66,7 @@ class Popen(object): def _launch(self, process_obj): code = 1
parent_r, child_w = util.pipe()[](#l11.7)
parent_r, child_w = os.pipe()[](#l11.8) self.pid = os.fork()[](#l11.9) if self.pid == 0:[](#l11.10) try:[](#l11.11)
--- a/Lib/multiprocessing/popen_spawn_posix.py +++ b/Lib/multiprocessing/popen_spawn_posix.py @@ -54,8 +54,8 @@ class Popen(popen_fork.Popen): parent_r = child_w = child_r = parent_w = None try:
parent_r, child_w = util.pipe()[](#l12.7)
child_r, parent_w = util.pipe()[](#l12.8)
parent_r, child_w = os.pipe()[](#l12.9)
child_r, parent_w = os.pipe()[](#l12.10) cmd = spawn.get_command_line(tracker_fd=tracker_fd,[](#l12.11) pipe_handle=child_r)[](#l12.12) self._fds.extend([child_r, child_w])[](#l12.13)
--- a/Lib/multiprocessing/semaphore_tracker.py +++ b/Lib/multiprocessing/semaphore_tracker.py @@ -45,7 +45,7 @@ def ensure_running(): except Exception: pass cmd = 'from multiprocessing.semaphore_tracker import main; main(%d)'
r, w = util.pipe()[](#l13.7)
r, w = os.pipe()[](#l13.8) try:[](#l13.9) fds_to_pass.append(r)[](#l13.10) # process will out live us, so no need to wait on pid[](#l13.11)
--- a/Lib/multiprocessing/util.py +++ b/Lib/multiprocessing/util.py @@ -365,7 +365,7 @@ def spawnv_passfds(path, args, passfds): if flag & fcntl.FD_CLOEXEC: fcntl.fcntl(fd, fcntl.F_SETFD, flag & ~fcntl.FD_CLOEXEC) tmp.append((fd, flag))
- errpipe_read, errpipe_write = os.pipe() try: return _posixsubprocess.fork_exec( args, [os.fsencode(path)], True, passfds, None, None,
@@ -381,7 +381,9 @@ def spawnv_passfds(path, args, passfds): #
Return pipe with CLOEXEC set on fds
# +# Deprecated: os.pipe() creates non-inheritable file descriptors +# since Python 3.4 +# def pipe():
--- a/Lib/socket.py +++ b/Lib/socket.py @@ -137,7 +137,8 @@ class socket(_socket.socket): def dup(self): """dup() -> socket object
Return a new socket object connected to the same system resource.[](#l15.7)
Duplicate the socket. Return a new socket object connected to the same[](#l15.8)
system resource. The new socket is non-inheritable.[](#l15.9) """[](#l15.10) fd = dup(self.fileno())[](#l15.11) sock = self.__class__(self.family, self.type, self.proto, fileno=fd)[](#l15.12)
@@ -229,6 +230,20 @@ class socket(_socket.socket): self._closed = True return super().detach()
- if os.name == 'nt':
def get_inheritable(self):[](#l15.18)
return os.get_handle_inheritable(self.fileno())[](#l15.19)
def set_inheritable(self, inheritable):[](#l15.20)
os.set_handle_inheritable(self.fileno(), inheritable)[](#l15.21)
- else:
def get_inheritable(self):[](#l15.23)
return os.get_inheritable(self.fileno())[](#l15.24)
def set_inheritable(self, inheritable):[](#l15.25)
os.set_inheritable(self.fileno(), inheritable)[](#l15.26)
- get_inheritable.doc = "Get the inheritable flag of the socket"
- set_inheritable.doc = "Set the inheritable flag of the socket"
+ + def fromfd(fd, family, type, proto=0): """ fromfd(fd, family, type[, proto]) -> socket object
--- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -405,7 +405,6 @@ else: import select _has_poll = hasattr(select, 'poll') import _posixsubprocess
# When select or poll has indicated that the file is writable, # we can write up to _PIPE_BUF bytes without risk of blocking. @@ -1258,7 +1257,7 @@ class Popen(object): if stdin is None: pass elif stdin == PIPE:
p2cread, p2cwrite = _create_pipe()[](#l16.15)
p2cread, p2cwrite = os.pipe()[](#l16.16) elif stdin == DEVNULL:[](#l16.17) p2cread = self._get_devnull()[](#l16.18) elif isinstance(stdin, int):[](#l16.19)
@@ -1270,7 +1269,7 @@ class Popen(object): if stdout is None: pass elif stdout == PIPE:
c2pread, c2pwrite = _create_pipe()[](#l16.24)
c2pread, c2pwrite = os.pipe()[](#l16.25) elif stdout == DEVNULL:[](#l16.26) c2pwrite = self._get_devnull()[](#l16.27) elif isinstance(stdout, int):[](#l16.28)
@@ -1282,7 +1281,7 @@ class Popen(object): if stderr is None: pass elif stderr == PIPE:
errread, errwrite = _create_pipe()[](#l16.33)
errread, errwrite = os.pipe()[](#l16.34) elif stderr == STDOUT:[](#l16.35) errwrite = c2pwrite[](#l16.36) elif stderr == DEVNULL:[](#l16.37)
@@ -1334,7 +1333,7 @@ class Popen(object): # For transferring possible exec failure from child to parent. # Data format: "exception name:hex errno:description" # Pickle is not used; it is complex and involves memory allocation.
errpipe_read, errpipe_write = _create_pipe()[](#l16.42)
errpipe_read, errpipe_write = os.pipe()[](#l16.43) try:[](#l16.44) try:[](#l16.45) # We must avoid complex work that could involve[](#l16.46)
--- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -35,33 +35,12 @@ import errno as _errno from random import Random as _Random try:
- def _set_cloexec(fd):
try:[](#l17.13)
flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)[](#l17.14)
except OSError:[](#l17.15)
pass[](#l17.16)
else:[](#l17.17)
# flags read successfully, modify[](#l17.18)
flags |= _fcntl.FD_CLOEXEC[](#l17.19)
_fcntl.fcntl(fd, _fcntl.F_SETFD, flags)[](#l17.20)
- - -try: import _thread except ImportError: import _dummy_thread as _thread _allocate_lock = _thread.allocate_lock _text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL -if hasattr(_os, 'O_CLOEXEC'):
-if hasattr(_os, 'O_NOINHERIT'):
if hasattr(_os, 'O_NOFOLLOW'): _text_openflags |= _os.O_NOFOLLOW @@ -90,8 +69,8 @@ else: # Fallback. All we need is something that raises OSError if the # file doesn't exist. def _stat(fn):
f = open(fn)[](#l17.41)
f.close()[](#l17.42)
fd = _os.open(fn, _os.O_RDONLY)[](#l17.43)
os.close(fd)[](#l17.44)
def _exists(fn): try: @@ -217,7 +196,6 @@ def _mkstemp_inner(dir, pre, suf, flags) file = _os.path.join(dir, pre + name + suf) try: fd = _os.open(file, flags, 0o600)
_set_cloexec(fd)[](#l17.52) return (fd, _os.path.abspath(file))[](#l17.53) except FileExistsError:[](#l17.54) continue # try again[](#l17.55)
new file mode 100644 --- /dev/null +++ b/Lib/test/subprocessdata/inherited.py @@ -0,0 +1,22 @@ +"""Similar to fd_status.py, but only checks file descriptors passed on the +command line.""" + +import errno +import os +import sys +import stat + +if name == "main":
- fds = map(int, sys.argv[1:])
- inherited = []
- for fd in fds:
try:[](#l18.17)
st = os.fstat(fd)[](#l18.18)
except OSError as e:[](#l18.19)
if e.errno == errno.EBADF:[](#l18.20)
continue[](#l18.21)
raise[](#l18.22)
# Ignore Solaris door files[](#l18.23)
if not stat.S_ISDOOR(st.st_mode):[](#l18.24)
inherited.append(fd)[](#l18.25)
- print(','.join(map(str, inherited)))
--- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -744,7 +744,12 @@ class BaseTestAPI: s.create_socket(self.family) self.assertEqual(s.socket.family, self.family) SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)
self.assertEqual(s.socket.type, socket.SOCK_STREAM | SOCK_NONBLOCK)[](#l19.7)
sock_type = socket.SOCK_STREAM | SOCK_NONBLOCK[](#l19.8)
if hasattr(socket, 'SOCK_CLOEXEC'):[](#l19.9)
self.assertIn(s.socket.type,[](#l19.10)
(sock_type | socket.SOCK_CLOEXEC, sock_type))[](#l19.11)
else:[](#l19.12)
self.assertEqual(s.socket.type, sock_type)[](#l19.13)
def test_bind(self): if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:
--- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1015,6 +1015,11 @@ class BuiltinTest(unittest.TestCase): os.environ.clear() os.environ.update(old_environ)
- def test_open_non_inheritable(self):
fileobj = open(__file__)[](#l20.8)
with fileobj:[](#l20.9)
self.assertFalse(os.get_inheritable(fileobj.fileno()))[](#l20.10)
+ def test_ord(self): self.assertEqual(ord(' '), 32) self.assertEqual(ord('A'), 65)
--- a/Lib/test/test_devpoll.py +++ b/Lib/test/test_devpoll.py @@ -2,7 +2,11 @@
Initial tests are copied as is from "test_poll.py"
-import os, select, random, unittest, sys +import os +import random +import select +import sys +import unittest from test.support import TESTFN, run_unittest try: @@ -111,6 +115,11 @@ class DevPollTests(unittest.TestCase): self.assertRaises(ValueError, devpoll.register, fd, fd, select.POLLIN) self.assertRaises(ValueError, devpoll.unregister, fd)
- def test_fd_non_inheritable(self):
devpoll = select.devpoll()[](#l21.21)
self.addCleanup(devpoll.close)[](#l21.22)
self.assertEqual(os.get_inheritable(devpoll.fileno()), False)[](#l21.23)
+ def test_main(): run_unittest(DevPollTests)
--- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -21,10 +21,11 @@ """ Tests for epoll wrapper. """ +import errno +import os +import select import socket -import errno import time -import select import unittest from test import support @@ -249,6 +250,11 @@ class TestEPoll(unittest.TestCase): self.assertRaises(ValueError, epoll.register, fd, select.EPOLLIN) self.assertRaises(ValueError, epoll.unregister, fd)
- def test_fd_non_inheritable(self):
epoll = select.epoll()[](#l22.22)
self.addCleanup(epoll.close)[](#l22.23)
self.assertEqual(os.get_inheritable(epoll.fileno()), False)[](#l22.24)
+ def test_main(): support.run_unittest(TestEPoll)
--- a/Lib/test/test_kqueue.py +++ b/Lib/test/test_kqueue.py @@ -206,6 +206,11 @@ class TestKQueue(unittest.TestCase): # operations must fail with ValueError("I/O operation on closed ...") self.assertRaises(ValueError, kqueue.control, None, 4)
- def test_fd_non_inheritable(self):
kqueue = select.kqueue()[](#l23.8)
self.addCleanup(kqueue.close)[](#l23.9)
self.assertEqual(os.get_inheritable(kqueue.fileno()), False)[](#l23.10)
+ def test_main(): support.run_unittest(TestKQueue)
--- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2298,6 +2298,72 @@ class CPUCountTests(unittest.TestCase): else: self.skipTest("Could not determine the number of CPUs") + +class FDInheritanceTests(unittest.TestCase):
- def test_get_inheritable(self):
fd = os.open(__file__, os.O_RDONLY)[](#l24.10)
self.addCleanup(os.close, fd)[](#l24.11)
for inheritable in (False, True):[](#l24.12)
os.set_inheritable(fd, inheritable)[](#l24.13)
self.assertEqual(os.get_inheritable(fd), inheritable)[](#l24.14)
- def test_set_inheritable(self):
fd = os.open(__file__, os.O_RDONLY)[](#l24.17)
self.addCleanup(os.close, fd)[](#l24.18)
os.set_inheritable(fd, True)[](#l24.19)
self.assertEqual(os.get_inheritable(fd), True)[](#l24.20)
- def test_open(self):
fd = os.open(__file__, os.O_RDONLY)[](#l24.23)
self.addCleanup(os.close, fd)[](#l24.24)
self.assertEqual(os.get_inheritable(fd), False)[](#l24.25)
- @unittest.skipUnless(hasattr(os, 'pipe'), "need os.pipe()")
- def test_pipe(self):
rfd, wfd = os.pipe()[](#l24.29)
self.addCleanup(os.close, rfd)[](#l24.30)
self.addCleanup(os.close, wfd)[](#l24.31)
self.assertEqual(os.get_inheritable(rfd), False)[](#l24.32)
self.assertEqual(os.get_inheritable(wfd), False)[](#l24.33)
- def test_dup(self):
fd1 = os.open(__file__, os.O_RDONLY)[](#l24.36)
self.addCleanup(os.close, fd1)[](#l24.37)
fd2 = os.dup(fd1)[](#l24.39)
self.addCleanup(os.close, fd2)[](#l24.40)
self.assertEqual(os.get_inheritable(fd2), False)[](#l24.41)
- @unittest.skipUnless(hasattr(os, 'dup2'), "need os.dup2()")
- def test_dup2(self):
fd = os.open(__file__, os.O_RDONLY)[](#l24.45)
self.addCleanup(os.close, fd)[](#l24.46)
# inheritable by default[](#l24.48)
fd2 = os.open(__file__, os.O_RDONLY)[](#l24.49)
try:[](#l24.50)
os.dup2(fd, fd2)[](#l24.51)
self.assertEqual(os.get_inheritable(fd2), True)[](#l24.52)
finally:[](#l24.53)
os.close(fd2)[](#l24.54)
# force non-inheritable[](#l24.56)
fd3 = os.open(__file__, os.O_RDONLY)[](#l24.57)
try:[](#l24.58)
os.dup2(fd, fd3, inheritable=False)[](#l24.59)
self.assertEqual(os.get_inheritable(fd3), False)[](#l24.60)
finally:[](#l24.61)
os.close(fd3)[](#l24.62)
- @unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
- def test_openpty(self):
master_fd, slave_fd = os.openpty()[](#l24.66)
self.addCleanup(os.close, master_fd)[](#l24.67)
self.addCleanup(os.close, slave_fd)[](#l24.68)
self.assertEqual(os.get_inheritable(master_fd), False)[](#l24.69)
self.assertEqual(os.get_inheritable(slave_fd), False)[](#l24.70)
+ + @support.reap_threads def test_main(): support.run_unittest( @@ -2330,6 +2396,7 @@ def test_main(): OSErrorTests, RemoveDirsTests, CPUCountTests,
--- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -23,10 +23,6 @@ import math import pickle import struct try:
-try: import multiprocessing except ImportError: multiprocessing = False @@ -1108,9 +1104,15 @@ class GeneralModuleTests(unittest.TestCa def testNewAttributes(self): # testing .family, .type and .protocol + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.assertEqual(sock.family, socket.AF_INET)
self.assertEqual(sock.type, socket.SOCK_STREAM)[](#l25.21)
if hasattr(socket, 'SOCK_CLOEXEC'):[](#l25.22)
self.assertIn(sock.type,[](#l25.23)
(socket.SOCK_STREAM | socket.SOCK_CLOEXEC,[](#l25.24)
socket.SOCK_STREAM))[](#l25.25)
else:[](#l25.26)
self.assertEqual(sock.type, socket.SOCK_STREAM)[](#l25.27) self.assertEqual(sock.proto, 0)[](#l25.28) sock.close()[](#l25.29)
@@ -4749,16 +4751,46 @@ class ContextManagersTest(ThreadedTCPSoc self.assertRaises(OSError, sock.sendall, b'foo') -@unittest.skipUnless(hasattr(socket, "SOCK_CLOEXEC"),
"SOCK_CLOEXEC not defined")[](#l25.36)
-@unittest.skipUnless(fcntl, "module fcntl not available") -class CloexecConstantTest(unittest.TestCase): +class InheritanceTest(unittest.TestCase):
- @unittest.skipUnless(hasattr(socket, "SOCK_CLOEXEC"),
@support.requires_linux_version(2, 6, 28) def test_SOCK_CLOEXEC(self): with socket.socket(socket.AF_INET, socket.SOCK_STREAM | socket.SOCK_CLOEXEC) as s: self.assertTrue(s.type & socket.SOCK_CLOEXEC)"SOCK_CLOEXEC not defined")[](#l25.41)
self.assertTrue(fcntl.fcntl(s, fcntl.F_GETFD) & fcntl.FD_CLOEXEC)[](#l25.47)
self.assertTrue(sock.get_inheritable())[](#l25.48)
- def test_default_inheritable(self):
sock = socket.socket()[](#l25.51)
with sock:[](#l25.52)
self.assertEqual(sock.get_inheritable(), False)[](#l25.53)
- def test_dup(self):
sock = socket.socket()[](#l25.56)
with sock:[](#l25.57)
newsock = sock.dup()[](#l25.58)
sock.close()[](#l25.59)
with newsock:[](#l25.60)
self.assertEqual(newsock.get_inheritable(), False)[](#l25.61)
- def test_set_inheritable(self):
sock = socket.socket()[](#l25.64)
with sock:[](#l25.65)
sock.set_inheritable(True)[](#l25.66)
self.assertEqual(sock.get_inheritable(), True)[](#l25.67)
sock.set_inheritable(False)[](#l25.69)
self.assertEqual(sock.get_inheritable(), False)[](#l25.70)
- @unittest.skipUnless(hasattr(socket, "socketpair"),
"need socket.socketpair()")[](#l25.73)
- def test_socketpair(self):
s1, s2 = socket.socketpair()[](#l25.75)
self.addCleanup(s1.close)[](#l25.76)
self.addCleanup(s2.close)[](#l25.77)
self.assertEqual(s1.get_inheritable(), False)[](#l25.78)
self.assertEqual(s2.get_inheritable(), False)[](#l25.79)
@unittest.skipUnless(hasattr(socket, "SOCK_NONBLOCK"), @@ -4927,7 +4959,7 @@ def test_main(): NetworkConnectionAttributesTest, NetworkConnectionBehaviourTest, ContextManagersTest,
CloexecConstantTest,[](#l25.87)
--- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1501,16 +1501,28 @@ class POSIXProcessTestCase(BaseTestCase) # Terminating a dead process self._kill_dead_process('terminate')
- def _save_fds(self, save_fds):
fds = [][](#l26.8)
for fd in save_fds:[](#l26.9)
inheritable = os.get_inheritable(fd)[](#l26.10)
saved = os.dup(fd)[](#l26.11)
fds.append((fd, saved, inheritable))[](#l26.12)
return fds[](#l26.13)
- def _restore_fds(self, fds):
for fd, saved, inheritable in fds:[](#l26.16)
os.dup2(saved, fd, inheritable=inheritable)[](#l26.17)
os.close(saved)[](#l26.18)
+ def check_close_std_fds(self, fds): # Issue #9905: test that subprocess pipes still work properly with # some standard fds closed stdin = 0
newfds = [][](#l26.24)
for a in fds:[](#l26.25)
b = os.dup(a)[](#l26.26)
newfds.append(b)[](#l26.27)
if a == 0:[](#l26.28)
stdin = b[](#l26.29)
saved_fds = self._save_fds(fds)[](#l26.30)
for fd, saved, inheritable in saved_fds:[](#l26.31)
if fd == 0:[](#l26.32)
stdin = saved[](#l26.33)
break[](#l26.34) try:[](#l26.35) for fd in fds:[](#l26.36) os.close(fd)[](#l26.37)
@@ -1525,10 +1537,7 @@ class POSIXProcessTestCase(BaseTestCase) err = support.strip_python_stderr(err) self.assertEqual((out, err), (b'apple', b'orange')) finally:
for b, a in zip(newfds, fds):[](#l26.42)
os.dup2(b, a)[](#l26.43)
for b in newfds:[](#l26.44)
os.close(b)[](#l26.45)
self._restore_fds(saved_fds)[](#l26.46)
def test_close_fd_0(self): self.check_close_std_fds([0]) @@ -1568,7 +1577,7 @@ class POSIXProcessTestCase(BaseTestCase) os.lseek(temp_fds[1], 0, 0) # move the standard file descriptors out of the way
saved_fds = [os.dup(fd) for fd in range(3)][](#l26.54)
saved_fds = self._save_fds(range(3))[](#l26.55) try:[](#l26.56) # duplicate the file objects over the standard fd's[](#l26.57) for fd, temp_fd in enumerate(temp_fds):[](#l26.58)
@@ -1584,10 +1593,7 @@ class POSIXProcessTestCase(BaseTestCase) stderr=temp_fds[0]) p.wait() finally:
# restore the original fd's underneath sys.stdin, etc.[](#l26.63)
for std, saved in enumerate(saved_fds):[](#l26.64)
os.dup2(saved, std)[](#l26.65)
os.close(saved)[](#l26.66)
self._restore_fds(saved_fds)[](#l26.67)
for fd in temp_fds: os.lseek(fd, 0, 0) @@ -1611,7 +1617,7 @@ class POSIXProcessTestCase(BaseTestCase) os.unlink(fname) # save a copy of the standard file descriptors
saved_fds = [os.dup(fd) for fd in range(3)][](#l26.75)
saved_fds = self._save_fds(range(3))[](#l26.76) try:[](#l26.77) # duplicate the temp files over the standard fd's 0, 1, 2[](#l26.78) for fd, temp_fd in enumerate(temp_fds):[](#l26.79)
@@ -1637,9 +1643,7 @@ class POSIXProcessTestCase(BaseTestCase) out = os.read(stdout_no, 1024) err = support.strip_python_stderr(os.read(stderr_no, 1024)) finally:
for std, saved in enumerate(saved_fds):[](#l26.84)
os.dup2(saved, std)[](#l26.85)
os.close(saved)[](#l26.86)
self._restore_fds(saved_fds)[](#l26.87)
self.assertEqual(out, b"got STDIN") self.assertEqual(err, b"err") @@ -1810,6 +1814,9 @@ class POSIXProcessTestCase(BaseTestCase) self.addCleanup(os.close, fd) open_fds.add(fd)
for fd in open_fds:[](#l26.95)
os.set_inheritable(fd, True)[](#l26.96)
+ p = subprocess.Popen([sys.executable, fd_status], stdout=subprocess.PIPE, close_fds=False) output, ignored = p.communicate() @@ -1854,6 +1861,8 @@ class POSIXProcessTestCase(BaseTestCase) fds = os.pipe() self.addCleanup(os.close, fds[0]) self.addCleanup(os.close, fds[1])
os.set_inheritable(fds[0], True)[](#l26.105)
os.set_inheritable(fds[1], True)[](#l26.106) open_fds.update(fds)[](#l26.107)
for fd in open_fds: @@ -1876,6 +1885,32 @@ class POSIXProcessTestCase(BaseTestCase) close_fds=False, pass_fds=(fd, ))) self.assertIn('overriding close_fds', str(context.warning))
- def test_pass_fds_inheritable(self):
script = support.findfile("inherited.py", subdir="subprocessdata")[](#l26.115)
inheritable, non_inheritable = os.pipe()[](#l26.117)
self.addCleanup(os.close, inheritable)[](#l26.118)
self.addCleanup(os.close, non_inheritable)[](#l26.119)
os.set_inheritable(inheritable, True)[](#l26.120)
os.set_inheritable(non_inheritable, False)[](#l26.121)
pass_fds = (inheritable, non_inheritable)[](#l26.122)
args = [sys.executable, script][](#l26.123)
args += list(map(str, pass_fds))[](#l26.124)
p = subprocess.Popen(args,[](#l26.126)
stdout=subprocess.PIPE, close_fds=True,[](#l26.127)
pass_fds=pass_fds)[](#l26.128)
output, ignored = p.communicate()[](#l26.129)
fds = set(map(int, output.split(b',')))[](#l26.130)
# the inheritable file descriptor must be inherited, so its inheritable[](#l26.132)
# flag must be set in the child process after fork() and before exec()[](#l26.133)
self.assertEqual(fds, set(pass_fds))[](#l26.134)
# inheritable flag must not be changed in the parent process[](#l26.136)
self.assertEqual(os.get_inheritable(inheritable), True)[](#l26.137)
self.assertEqual(os.get_inheritable(non_inheritable), False)[](#l26.138)
+ def test_stdout_stdin_are_single_inout_fd(self): with io.open(os.devnull, "r+") as inout: p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"],
--- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -333,6 +333,7 @@ class TestMkstempInner(BaseTestCase): v="q" file = self.do_create()
self.assertEqual(os.get_inheritable(file.fd), False)[](#l27.7) fd = "%d" % file.fd[](#l27.8)
--- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -584,13 +584,6 @@ class SimpleXMLRPCServer(socketserver.TC SimpleXMLRPCDispatcher.init(self, allow_none, encoding, use_builtin_types) socketserver.TCPServer.init(self, addr, requestHandler, bind_and_activate)
# [Bug #1222790] If possible, set close-on-exec flag; if a[](#l28.7)
# method spawns a subprocess, the subprocess shouldn't have[](#l28.8)
# the listening socket open.[](#l28.9)
if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):[](#l28.10)
flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)[](#l28.11)
flags |= fcntl.FD_CLOEXEC[](#l28.12)
fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)[](#l28.13)
class MultiPathXMLRPCServer(SimpleXMLRPCServer): """Multipath XML-RPC Server
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Projected Release date: 2013-09-08 Core and Builtins ----------------- +- Issue #18571: Implementation of the PEP 446: file descriptors and file
- handles are now created non-inheritable; add functions
- os.get/set_inheritable(), os.get/set_handle_inheritable() and
- socket.socket.get/set_inheritable(). +
- Issue #11619: The parser and the import machinery do not encode Unicode filenames anymore on Windows.
--- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1694,26 +1694,24 @@ PyCursesWindow_PutWin(PyCursesWindowObje /* We have to simulate this by writing to a temporary FILE*, then reading back, then writing to the argument stream. */ char fn[100];
strcpy(fn, "/tmp/py.curses.putwin.XXXXXX"); fd = mkstemp(fn); if (fd < 0) return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
- if (_Py_set_inheritable(fd, 0, NULL) < 0)
fp = fdopen(fd, "wb+"); if (fp == NULL) {goto exit;[](#l30.19)
close(fd);[](#l30.22)
remove(fn);[](#l30.23)
return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);[](#l30.24)
PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);[](#l30.25)
} res = PyCursesCheckERR(putwin(self->win, fp), "putwin");goto exit;[](#l30.26)
@@ -1727,7 +1725,12 @@ PyCursesWindow_PutWin(PyCursesWindowObje if (res == NULL) break; }
- if (fp != NULL)
fclose(fp);[](#l30.47)
- else if (fd != -1)
remove(fn); return res; } @@ -2252,12 +2255,13 @@ static PyObject * PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream) { char fn[100];close(fd);[](#l30.49)
- int fd = -1;
- FILE *fp = NULL; PyObject *data; size_t datalen; WINDOW *win; _Py_IDENTIFIER(read);
- PyObject *res = NULL;
PyCursesInitialised; @@ -2265,44 +2269,47 @@ PyCurses_GetWin(PyCursesWindowObject *se fd = mkstemp(fn); if (fd < 0) return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
- if (_Py_set_inheritable(fd, 0, NULL) < 0)
fp = fdopen(fd, "wb+"); if (fp == NULL) {goto error;[](#l30.74)
close(fd);[](#l30.77)
remove(fn);[](#l30.78)
return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);[](#l30.79)
PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);[](#l30.80)
} + data = _PyObject_CallMethodId(stream, &PyId_read, "");goto error;[](#l30.81)
- if (data == NULL)
if (!PyBytes_Check(data)) { PyErr_Format(PyExc_TypeError, "f.read() returned %.100s instead of bytes", data->ob_type->tp_name); Py_DECREF(data);goto error;[](#l30.91)
fclose(fp);[](#l30.97)
remove(fn);[](#l30.98)
return NULL;[](#l30.99)
} datalen = PyBytes_GET_SIZE(data); if (fwrite(PyBytes_AS_STRING(data), 1, datalen, fp) != datalen) { Py_DECREF(data);goto error;[](#l30.100)
fclose(fp);[](#l30.105)
remove(fn);[](#l30.106)
return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);[](#l30.107)
PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);[](#l30.108)
} Py_DECREF(data); + fseek(fp, 0, 0); win = getwin(fp);goto error;[](#l30.109)
- fclose(fp);
- remove(fn); if (win == NULL) { PyErr_SetString(PyCursesError, catchall_NULL);
return NULL;[](#l30.119)
- if (fp != NULL)
fclose(fp);[](#l30.127)
- else if (fd != -1)
close(fd);[](#l30.129)
- remove(fn);
- return res;
--- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -202,6 +202,9 @@ check_fd(int fd) return 0; } +#ifdef O_CLOEXEC +extern int _Py_open_cloexec_works; +#endif static int fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) @@ -221,6 +224,11 @@ fileio_init(PyObject *oself, PyObject *a int fd = -1; int closefd = 1; int fd_is_own = 0; +#ifdef O_CLOEXEC
+#endif assert(PyFileIO_Check(oself)); if (self->fd >= 0) { @@ -345,6 +353,11 @@ fileio_init(PyObject *oself, PyObject *a if (append) flags |= O_APPEND; #endif +#ifdef MS_WINDOWS
+#endif if (fd >= 0) { if (check_fd(fd)) @@ -369,10 +382,18 @@ fileio_init(PyObject *oself, PyObject *a else #endif self->fd = open(name, flags, 0666); + Py_END_ALLOW_THREADS
} else {[](#l31.43)
PyObject *fdobj = PyObject_CallFunction([](#l31.44)
opener, "Oi", nameobj, flags);[](#l31.45)
}[](#l31.46)
else {[](#l31.47)
PyObject *fdobj;[](#l31.48)
/* the opener may clear the atomic flag */[](#l31.51)
atomic_flag_works = NULL;[](#l31.52)
fdobj = PyObject_CallFunction(opener, "Oi", nameobj, flags);[](#l31.55) if (fdobj == NULL)[](#l31.56) goto error;[](#l31.57) if (!PyLong_Check(fdobj)) {[](#l31.58)
@@ -394,6 +415,11 @@ fileio_init(PyObject *oself, PyObject *a PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); goto error; } + +#ifndef MS_WINDOWS
if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0)[](#l31.65)
goto error;[](#l31.66)
+#endif } if (dircheck(self, nameobj) < 0) goto error;
--- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -35,7 +35,7 @@
define FD_DIR "/proc/self/fd"
#endif -#define POSIX_CALL(call) if ((call) == -1) goto error +#define POSIX_CALL(call) do { if ((call) == -1) goto error; } while (0) /* Maximum file descriptor, initialized on module load. */ @@ -87,7 +87,7 @@ static int if (stat("/dev", &dev_stat) != 0) return 0; if (stat(FD_DIR, &dev_fd_stat) != 0)
return 0; [](#l32.16)
if (dev_stat.st_dev == dev_fd_stat.st_dev) return 0; /* / == /dev == /dev/fd means it is static. #fail */ return 1; @@ -136,6 +136,29 @@ static int return 0; } +static int +make_inheritable(PyObject *py_fds_to_keep, int errpipe_write) +{return 0;[](#l32.17)
- Py_ssize_t i, len;
- len = PySequence_Length(py_fds_to_keep);
- for (i = 0; i < len; ++i) {
PyObject* fdobj = PySequence_Fast_GET_ITEM(py_fds_to_keep, i);[](#l32.32)
long fd = PyLong_AsLong(fdobj);[](#l32.33)
assert(!PyErr_Occurred());[](#l32.34)
assert(0 <= fd && fd <= INT_MAX);[](#l32.35)
if (fd == errpipe_write) {[](#l32.36)
/* errpipe_write is part of py_fds_to_keep. It must be closed at[](#l32.37)
exec(), but kept open in the child process until exec() is[](#l32.38)
called. */[](#l32.39)
continue;[](#l32.40)
}[](#l32.41)
if (_Py_set_inheritable((int)fd, 1, NULL) < 0)[](#l32.42)
return -1;[](#l32.43)
- }
- return 0;
+} + /* Close all file descriptors in the range start_fd inclusive to
- end_fd exclusive except for those in py_fds_to_keep. If the @@ -205,18 +228,8 @@ static void int fd_dir_fd; if (start_fd >= end_fd) return;
- {
int old = fcntl(fd_dir_fd, F_GETFD);[](#l32.61)
if (old != -1)[](#l32.62)
fcntl(fd_dir_fd, F_SETFD, old | FD_CLOEXEC);[](#l32.63)
- }
- fd_dir_fd = _Py_open(FD_DIR, O_RDONLY); if (fd_dir_fd == -1) { /* No way to get a list of open fds. */ _close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep);
@@ -356,16 +369,16 @@ child_exec(char const exec_array[], / Buffer large enough to hold a hex integer. We can't malloc. */ char hex_errno[sizeof(saved_errno)*2+1];
+ /* Close parent's pipe ends. */
- } POSIX_CALL(close(errpipe_read)); /* When duping fds, if there arises a situation where one of the fds is @@ -379,38 +392,34 @@ child_exec(char *const exec_array[], dup2() removes the CLOEXEC flag but we must do it ourselves if dup2() would be a no-op (issue #10806). */ if (p2cread == 0) {
int old = fcntl(p2cread, F_GETFD);[](#l32.99)
if (old != -1)[](#l32.100)
fcntl(p2cread, F_SETFD, old & ~FD_CLOEXEC);[](#l32.101)
- } else if (p2cread != -1) {
if (_Py_set_inheritable(p2cread, 1, NULL) < 0)[](#l32.103)
goto error;[](#l32.104)
- }
- else if (p2cread != -1) POSIX_CALL(dup2(p2cread, 0)); /* stdin */
int old = fcntl(c2pwrite, F_GETFD);[](#l32.111)
if (old != -1)[](#l32.112)
fcntl(c2pwrite, F_SETFD, old & ~FD_CLOEXEC);[](#l32.113)
- } else if (c2pwrite != -1) {
if (_Py_set_inheritable(c2pwrite, 1, NULL) < 0)[](#l32.115)
goto error;[](#l32.116)
- }
- else if (c2pwrite != -1) POSIX_CALL(dup2(c2pwrite, 1)); /* stdout */
int old = fcntl(errwrite, F_GETFD);[](#l32.123)
if (old != -1)[](#l32.124)
fcntl(errwrite, F_SETFD, old & ~FD_CLOEXEC);[](#l32.125)
- } else if (errwrite != -1) {
if (_Py_set_inheritable(errwrite, 1, NULL) < 0)[](#l32.127)
goto error;[](#l32.128)
- }
- else if (errwrite != -1) POSIX_CALL(dup2(errwrite, 2)); /* stderr */
/* Close pipe fds. Make sure we don't close the same fd more than / / once, or standard fds. */
if (cwd) POSIX_CALL(chdir(cwd)); @@ -544,7 +553,7 @@ subprocess_fork_exec(PyObject* self, PyO PyObject *result; _Py_IDENTIFIER(isenabled); _Py_IDENTIFIER(disable);
[](#l32.155)
+ gc_module = PyImport_ImportModule("gc"); if (gc_module == NULL) return NULL; @@ -721,52 +730,6 @@ Returns: the child process's PID.\n[](#l32.160) Raises: Only on an error in the parent process.\n[](#l32.161) "); -PyDoc_STRVAR(subprocess_cloexec_pipe_doc, -"cloexec_pipe() -> (read_end, write_end)\n\n[](#l32.165) -Create a pipe whose ends have the cloexec flag set."); - -static PyObject * -subprocess_cloexec_pipe(PyObject *self, PyObject *noargs) -{
- Py_BEGIN_ALLOW_THREADS
- res = pipe2(fds, O_CLOEXEC);
- Py_END_ALLOW_THREADS
- if (res != 0 && errno == ENOSYS)
- {
{[](#l32.179)
/* We hold the GIL which offers some protection from other code calling[](#l32.181)
* fork() before the CLOEXEC flags have been set but we can't guarantee[](#l32.182)
* anything without pipe2(). */[](#l32.183)
long oldflags;[](#l32.184)
res = pipe(fds);[](#l32.186)
if (res == 0) {[](#l32.188)
oldflags = fcntl(fds[0], F_GETFD, 0);[](#l32.189)
if (oldflags < 0) res = oldflags;[](#l32.190)
}[](#l32.191)
if (res == 0)[](#l32.192)
res = fcntl(fds[0], F_SETFD, oldflags | FD_CLOEXEC);[](#l32.193)
if (res == 0) {[](#l32.195)
oldflags = fcntl(fds[1], F_GETFD, 0);[](#l32.196)
if (oldflags < 0) res = oldflags;[](#l32.197)
}[](#l32.198)
if (res == 0)[](#l32.199)
res = fcntl(fds[1], F_SETFD, oldflags | FD_CLOEXEC);[](#l32.200)
- if (res != 0)
return PyErr_SetFromErrno(PyExc_OSError);[](#l32.206)
- return Py_BuildValue("(ii)", fds[0], fds[1]);
-} - /* module level code ********************************************************/ PyDoc_STRVAR(module_doc, @@ -775,7 +738,6 @@ PyDoc_STRVAR(module_doc, static PyMethodDef module_methods[] = { {"fork_exec", subprocess_fork_exec, METH_VARARGS, subprocess_fork_exec_doc},
- {"cloexec_pipe", subprocess_cloexec_pipe, METH_NOARGS, subprocess_cloexec_pipe_doc}, {NULL, NULL} /* sentinel */ };
--- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2350,7 +2350,7 @@ load_dh_params(PySSLContext *self, PyObj FILE *f; DH *dh;
- f = _Py_fopen_obj(filepath, "rb"); if (f == NULL) { if (!PyErr_Occurred()) PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath);
--- a/Modules/main.c +++ b/Modules/main.c @@ -143,7 +143,7 @@ static void RunStartupFile(PyCompilerFla { char *startup = Py_GETENV("PYTHONSTARTUP"); if (startup != NULL && startup[0] != '\0') {
FILE *fp = fopen(startup, "r");[](#l34.7)
FILE *fp = _Py_fopen(startup, "r");[](#l34.8) if (fp != NULL) {[](#l34.9) (void) PyRun_SimpleFileExFlags(fp, startup, 0, cf);[](#l34.10) PyErr_Clear();[](#l34.11)
--- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1208,18 +1208,18 @@ new_mmap_object(PyTypeObject type, PyOb flags |= MAP_ANONYMOUS; #else / SVR4 method to map anonymous memory is to open /dev/zero */
fd = devzero = open("/dev/zero", O_RDWR);[](#l35.7)
fd = devzero = _Py_open("/dev/zero", O_RDWR);[](#l35.8) if (devzero == -1) {[](#l35.9) Py_DECREF(m_obj);[](#l35.10) PyErr_SetFromErrno(PyExc_OSError);[](#l35.11) return NULL;[](#l35.12) }[](#l35.13)
- }
- else {
m_obj->fd = _Py_dup(fd);[](#l35.19) if (m_obj->fd == -1) {[](#l35.20) Py_DECREF(m_obj);[](#l35.21)
--- a/Modules/ossaudiodev.c +++ b/Modules/ossaudiodev.c @@ -115,7 +115,9 @@ newossobject(PyObject *arg) one open at a time. This does not affect later I/O; OSS provides a special ioctl() for non-blocking read/write, which is exposed via oss_nonblock() below. */
- if (fd == -1) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename); return NULL; } @@ -177,7 +179,8 @@ newossmixerobject(PyObject *arg) devicename = "/dev/mixer"; }
- fd = _Py_open(devicename, O_RDWR);
- if (fd == -1) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename); return NULL; }
--- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3535,10 +3535,7 @@ static PyObject #ifdef HAVE_FDOPENDIR if (path->fd != -1) { / closedir() closes the FD, so we duplicate it */
Py_BEGIN_ALLOW_THREADS[](#l37.7)
fd = dup(path->fd);[](#l37.8)
Py_END_ALLOW_THREADS[](#l37.9)
fd = _Py_dup(path->fd);[](#l37.11) if (fd == -1) {[](#l37.12) list = posix_error();[](#l37.13) goto exit;[](#l37.14)
@@ -5768,7 +5765,7 @@ Open a pseudo-terminal, returning open f static PyObject * posix_openpty(PyObject *self, PyObject *noargs) {
#ifndef HAVE_OPENPTY char * slave_name; #endif @@ -5781,37 +5778,52 @@ posix_openpty(PyObject *self, PyObject * #ifdef HAVE_OPENPTY if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0)
return posix_error();[](#l37.28)
goto posix_error;[](#l37.29)
- if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
goto error;[](#l37.32)
- if (_Py_set_inheritable(slave_fd, 0, NULL) < 0)
goto error;[](#l37.34)
+ #elif defined(HAVE__GETPTY) slave_name = _getpty(&master_fd, O_RDWR, 0666, 0); if (slave_name == NULL)
return posix_error();[](#l37.39)
goto posix_error;[](#l37.42)
- if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
goto error;[](#l37.44)
return posix_error();[](#l37.48)
goto posix_error;[](#l37.51)
return posix_error();[](#l37.56)
goto posix_error;[](#l37.57)
+ sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL); + /* change permission of slave */ if (grantpt(master_fd) < 0) { PyOS_setsig(SIGCHLD, sig_saved);
+ /* unlock slave */ if (unlockpt(master_fd) < 0) { PyOS_setsig(SIGCHLD, sig_saved);
+ PyOS_setsig(SIGCHLD, sig_saved); + slave_name = ptsname(master_fd); /* get name of slave */ if (slave_name == NULL)
goto posix_error;[](#l37.83)
return posix_error();[](#l37.87)
goto posix_error;[](#l37.88)
#if !defined(CYGWIN) && !defined(HAVE_DEV_PTC) ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem / ioctl(slave_fd, I_PUSH, "ldterm"); / push ldterm */ @@ -5823,6 +5835,14 @@ posix_openpty(PyObject *self, PyObject * return Py_BuildValue("(ii)", master_fd, slave_fd); +posix_error:
- if (master_fd != -1)
close(master_fd);[](#l37.100)
- if (slave_fd != -1)
close(slave_fd);[](#l37.102)
- return NULL;
} #endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */ @@ -7432,6 +7452,10 @@ posix_tcsetpgrp(PyObject self, PyObject / Functions acting on file descriptors */ +#ifdef O_CLOEXEC +extern int Py_open_cloexec_works; +#endif + PyDoc_STRVAR(posix_open__doc_, "open(path, flags, mode=0o777, *, dir_fd=None)\n\n[](#l37.116) Open a file for low level IO. Returns a file handle (integer).\n[](#l37.117) @@ -7451,6 +7475,11 @@ posix_open(PyObject *self, PyObject *arg int fd; PyObject *return_value = NULL; static char *keywords[] = {"path", "flags", "mode", "dir_fd", NULL}; +#ifdef O_CLOEXEC
+#endif memset(&path, 0, sizeof(path)); path.function_name = "open"; @@ -7465,6 +7494,12 @@ posix_open(PyObject *self, PyObject *arg )) return NULL; +#ifdef MS_WINDOWS
+#endif + Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS if (path.wide) @@ -7484,6 +7519,13 @@ posix_open(PyObject *self, PyObject *arg goto exit; } +#ifndef MS_WINDOWS
- if (_Py_set_inheritable(fd, 0, atomic_flag_works) < 0) {
close(fd);[](#l37.149)
goto exit;[](#l37.150)
- }
+#endif + return_value = PyLong_FromLong((long)fd); exit: @@ -7540,13 +7582,14 @@ static PyObject * posix_dup(PyObject *self, PyObject *args) { int fd; + if (!PyArg_ParseTuple(args, "i:dup", &fd)) return NULL;
- if (!_PyVerify_fd(fd))
return posix_error();[](#l37.165)
- fd = dup(fd);
- if (fd < 0)
return posix_error();[](#l37.168)
+ return PyLong_FromLong((long)fd); } @@ -7556,16 +7599,82 @@ PyDoc_STRVAR(posix_dup2__doc__, Duplicate file descriptor."); static PyObject * -posix_dup2(PyObject *self, PyObject *args) -{
+posix_dup2(PyObject *self, PyObject *args, PyObject *kwargs) +{
- static char *keywords[] = {"fd", "fd2", "inheritable", NULL};
- int fd, fd2;
- int inheritable = 1;
- int res;
+#if defined(HAVE_DUP3) && [](#l37.192)
- !(defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC))
- /* dup3() is available on Linux 2.6.27+ and glibc 2.9 */
- int dup3_works = -1;
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|i:dup2", keywords,
&fd, &fd2, &inheritable))[](#l37.199)
return NULL;[](#l37.200)
+ if (!_PyVerify_fd_dup2(fd, fd2)) return posix_error(); + +#ifdef MS_WINDOWS
- Py_BEGIN_ALLOW_THREADS res = dup2(fd, fd2);
- Py_END_ALLOW_THREADS
- if (res < 0)
return posix_error();[](#l37.210)
- /* Character files like console cannot be make non-inheritable */
- if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
close(fd2);[](#l37.214)
return NULL;[](#l37.215)
- }
+ +#elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)
- Py_BEGIN_ALLOW_THREADS
- if (!inheritable)
res = fcntl(fd, F_DUP2FD_CLOEXEC, fd2);[](#l37.221)
- else
res = dup2(fd, fd2);[](#l37.223)
- Py_END_ALLOW_THREADS if (res < 0) return posix_error();
- if (!inheritable && dup3_works != 0) {
Py_BEGIN_ALLOW_THREADS[](#l37.232)
res = dup3(fd, fd2, O_CLOEXEC);[](#l37.233)
Py_END_ALLOW_THREADS[](#l37.234)
if (res < 0) {[](#l37.235)
if (dup3_works == -1)[](#l37.236)
dup3_works = (errno != ENOSYS);[](#l37.237)
if (dup3_works)[](#l37.238)
return posix_error();[](#l37.239)
}[](#l37.240)
- }
Py_BEGIN_ALLOW_THREADS[](#l37.246)
res = dup2(fd, fd2);[](#l37.247)
Py_END_ALLOW_THREADS[](#l37.248)
if (res < 0)[](#l37.249)
return posix_error();[](#l37.250)
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {[](#l37.252)
close(fd2);[](#l37.253)
return NULL;[](#l37.254)
}[](#l37.255)
+#endif + +#endif + Py_INCREF(Py_None); return Py_None; } @@ -8052,24 +8161,69 @@ Create a pipe."); static PyObject * posix_pipe(PyObject *self, PyObject *noargs) { -#if !defined(MS_WINDOWS) int fds[2]; +#ifdef MS_WINDOWS
- res = pipe(fds);
- if (res != 0)
return posix_error();[](#l37.279)
- return Py_BuildValue("(ii)", fds[0], fds[1]);
- Py_BEGIN_ALLOW_THREADS
- ok = CreatePipe(&read, &write, &attr, 0);
- if (ok) {
fds[0] = _open_osfhandle((Py_intptr_t)read, _O_RDONLY);[](#l37.296)
fds[1] = _open_osfhandle((Py_intptr_t)write, _O_WRONLY);[](#l37.297)
if (fds[0] == -1 || fds[1] == -1) {[](#l37.298)
CloseHandle(read);[](#l37.299)
CloseHandle(write);[](#l37.300)
ok = 0;[](#l37.301)
}[](#l37.302)
- }
- Py_END_ALLOW_THREADS
+ if (!ok) return PyErr_SetFromWindowsErr(0);
- read_fd = _open_osfhandle((Py_intptr_t)read, 0);
- write_fd = _open_osfhandle((Py_intptr_t)write, 1);
- return Py_BuildValue("(ii)", read_fd, write_fd);
-#endif /* MS_WINDOWS */ +#else + +#ifdef HAVE_PIPE2
Py_BEGIN_ALLOW_THREADS[](#l37.322)
res = pipe(fds);[](#l37.323)
Py_END_ALLOW_THREADS[](#l37.324)
if (res == 0) {[](#l37.326)
if (_Py_set_inheritable(fds[0], 0, NULL) < 0) {[](#l37.327)
close(fds[0]);[](#l37.328)
close(fds[1]);[](#l37.329)
return NULL;[](#l37.330)
}[](#l37.331)
if (_Py_set_inheritable(fds[1], 0, NULL) < 0) {[](#l37.332)
close(fds[0]);[](#l37.333)
close(fds[1]);[](#l37.334)
return NULL;[](#l37.335)
}[](#l37.336)
}[](#l37.337)
} #endif /* HAVE_PIPE */ @@ -10659,6 +10813,102 @@ posix_cpu_count(PyObject *self) Py_RETURN_NONE; } +PyDoc_STRVAR(get_inheritable__doc__,
- "get_inheritable(fd) -> bool\n" [](#l37.354)
- "\n" [](#l37.355)
- "Get the close-on-exe flag of the specified file descriptor.");
+ +static PyObject* +posix_get_inheritable(PyObject *self, PyObject *args) +{
- inheritable = _Py_get_inheritable(fd);
- if (inheritable < 0)
return NULL;[](#l37.372)
- return PyBool_FromLong(inheritable);
+} + +PyDoc_STRVAR(set_inheritable__doc__,
- "set_inheritable(fd, inheritable)\n" [](#l37.377)
- "\n" [](#l37.378)
- "Set the inheritable flag of the specified file descriptor.");
+ +static PyObject* +posix_set_inheritable(PyObject *self, PyObject *args) +{
+} + + +#ifdef MS_WINDOWS +PyDoc_STRVAR(get_handle_inheritable__doc__,
- "get_handle_inheritable(fd) -> bool\n" [](#l37.400)
- "\n" [](#l37.401)
- "Get the close-on-exe flag of the specified file descriptor.");
+ +static PyObject* +posix_get_handle_inheritable(PyObject *self, PyObject *args) +{
- if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR ":get_handle_inheritable", &handle))
return NULL;[](#l37.411)
- if (!GetHandleInformation((HANDLE)handle, &flags)) {
PyErr_SetFromWindowsErr(0);[](#l37.414)
return NULL;[](#l37.415)
- }
+} + +PyDoc_STRVAR(set_handle_inheritable__doc__,
- "set_handle_inheritable(fd, inheritable)\n" [](#l37.422)
- "\n" [](#l37.423)
- "Set the inheritable flag of the specified handle.");
+ +static PyObject* +posix_set_handle_inheritable(PyObject *self, PyObject *args) +{
- if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR "i:set_handle_inheritable",
&handle, &inheritable))[](#l37.434)
return NULL;[](#l37.435)
- if (inheritable)
flags = HANDLE_FLAG_INHERIT;[](#l37.438)
- else
flags = 0;[](#l37.440)
- if (!SetHandleInformation((HANDLE)handle, HANDLE_FLAG_INHERIT, flags)) {
PyErr_SetFromWindowsErr(0);[](#l37.442)
return NULL;[](#l37.443)
- }
- Py_RETURN_NONE;
+} +#endif /* MS_WINDOWS */ + static PyMethodDef posix_methods[] = { {"access", (PyCFunction)posix_access, @@ -10934,7 +11184,8 @@ static PyMethodDef posix_methods[] = { {"closerange", posix_closerange, METH_VARARGS, posix_closerange__doc__}, {"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__}, {"dup", posix_dup, METH_VARARGS, posix_dup__doc__},
#ifdef HAVE_LOCKF {"lockf", posix_lockf, METH_VARARGS, posix_lockf__doc__}, #endif @@ -11105,6 +11356,14 @@ static PyMethodDef posix_methods[] = { #endif {"cpu_count", (PyCFunction)posix_cpu_count, METH_NOARGS, posix_cpu_count__doc__},
- {"get_inheritable", posix_get_inheritable, METH_VARARGS, get_inheritable__doc__},
- {"set_inheritable", posix_set_inheritable, METH_VARARGS, set_inheritable__doc__},
- {"get_handle_inheritable", posix_get_handle_inheritable,
METH_VARARGS, get_handle_inheritable__doc__},[](#l37.470)
- {"set_handle_inheritable", posix_set_handle_inheritable,
METH_VARARGS, set_handle_inheritable__doc__},[](#l37.472)
+#endif {NULL, NULL} /* Sentinel */ };
--- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1004,7 +1004,7 @@ newDevPollObject(void) */ limit_result = getrlimit(RLIMIT_NOFILE, &limit); if (limit_result != -1)
fd_devpoll = open("/dev/poll", O_RDWR);[](#l38.7)
Py_END_ALLOW_THREADS if (limit_result == -1) { @@ -1194,6 +1194,7 @@ newPyEpoll_Object(PyTypeObject *type, in if (fd == -1) { Py_BEGIN_ALLOW_THREADSfd_devpoll = _Py_open("/dev/poll", O_RDWR);[](#l38.8)
flags |= EPOLL_CLOEXEC;[](#l38.16) if (flags)[](#l38.17) self->epfd = epoll_create1(flags);[](#l38.18) else[](#l38.19)
@@ -1209,6 +1210,14 @@ newPyEpoll_Object(PyTypeObject *type, in PyErr_SetFromErrno(PyExc_OSError); return NULL; } + +#ifndef HAVE_EPOLL_CREATE1
- if (_Py_set_inheritable(self->epfd, 0, NULL) < 0) {
Py_DECREF(self);[](#l38.27)
return NULL;[](#l38.28)
- }
+#endif + return (PyObject *)self; } @@ -1896,13 +1905,19 @@ newKqueue_Object(PyTypeObject *type, SOC PyErr_SetFromErrno(PyExc_OSError); return NULL; } +
- if (fd == -1) {
if (_Py_set_inheritable(self->kqfd, 0, NULL) < 0) {[](#l38.41)
Py_DECREF(self);[](#l38.42)
return NULL;[](#l38.43)
}[](#l38.44)
- } return (PyObject *)self; }
static PyObject * kqueue_queue_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - if ((args != NULL && PyObject_Size(args)) || (kwds != NULL && PyObject_Size(kwds))) { PyErr_SetString(PyExc_ValueError,
--- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -97,13 +97,14 @@ Local naming conventions: /* Socket object documentation / PyDoc_STRVAR(sock_doc, -"socket([family[, type[, proto]]]) -> socket object\n[](#l39.7) +"socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) -> socket object\n[](#l39.8) \n[](#l39.9) Open a socket of the given type. The family argument specifies the\n[](#l39.10) address family; it defaults to AF_INET. The type argument specifies\n[](#l39.11) whether this is a stream (SOCK_STREAM, this is the default)\n[](#l39.12) or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0,\n[](#l39.13) specifying the default protocol. Keyword arguments are accepted.\n[](#l39.14) +The socket is created as non-inheritable.\n[](#l39.15) \n[](#l39.16) A socket object represents one endpoint of a network connection.\n[](#l39.17) \n[](#l39.18) @@ -114,7 +115,7 @@ bind(addr) -- bind the socket to a local close() -- close the socket\n[](#l39.20) connect(addr) -- connect the socket to a remote address\n[](#l39.21) connect_ex(addr) -- connect, return an error code instead of an exception\n[](#l39.22) -_dup() -- return a new socket fd duplicated from fileno()\n[](#l39.23) +dup() -- return a new socket fd duplicated from fileno()\n[](#l39.24) fileno() -- return underlying file descriptor\n[](#l39.25) getpeername() -- return remote address []\n[](#l39.26) getsockname() -- return local address\n[](#l39.27) @@ -356,22 +357,7 @@ const char inet_ntop(int af, const void #endif #ifdef MS_WINDOWS -/ On Windows a socket is really a handle not an fd */ -static SOCKET -dup_socket(SOCKET handle) -{
- return WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, &info, 0, WSA_FLAG_OVERLAPPED);[](#l39.42)
-} #define SOCKETCLOSE closesocket -#else -/* On Unix we can use dup to duplicate the file descriptor of a socket*/ -#define dup_socket(fd) dup(fd) #endif #ifdef MS_WIN32 @@ -499,6 +485,11 @@ select_error(void) (errno == expected) #endif +#ifdef MS_WINDOWS +/* Does WSASocket() support the WSA_FLAG_NO_HANDLE_INHERIT flag? / +static int support_wsa_no_inherit = -1; +#endif + / Convenience function to raise an error according to errno and return a NULL pointer from a function. */ @@ -1955,6 +1946,11 @@ sock_accept(PySocketSockObject *s) PyObject *addr = NULL; PyObject *res = NULL; int timeout; +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
+#endif + if (!getsockaddrlen(s, &addrlen)) return NULL; memset(&addrbuf, 0, addrlen); @@ -1963,10 +1959,24 @@ sock_accept(PySocketSockObject *s) return select_error(); BEGIN_SELECT_LOOP(s) + Py_BEGIN_ALLOW_THREADS timeout = internal_select_ex(s, 0, interval); if (!timeout) { +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
if (accept4_works != 0) {[](#l39.84)
newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen,[](#l39.85)
SOCK_CLOEXEC);[](#l39.86)
if (newfd == INVALID_SOCKET && accept4_works == -1) {[](#l39.87)
/* On Linux older than 2.6.28, accept4() fails with ENOSYS */[](#l39.88)
accept4_works = (errno != ENOSYS);[](#l39.89)
}[](#l39.90)
}[](#l39.91)
if (accept4_works == 0)[](#l39.92)
newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);[](#l39.93)
+#else newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); +#endif } Py_END_ALLOW_THREADS @@ -1979,6 +1989,25 @@ sock_accept(PySocketSockObject *s) if (newfd == INVALID_SOCKET) return s->errorhandler(); +#ifdef MS_WINDOWS
- if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) {
PyErr_SetFromWindowsErr(0);[](#l39.106)
SOCKETCLOSE(newfd);[](#l39.107)
goto finally;[](#l39.108)
- }
+#else + +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
- {
if (_Py_set_inheritable(newfd, 0, NULL) < 0) {[](#l39.116)
SOCKETCLOSE(newfd);[](#l39.117)
goto finally;[](#l39.118)
}[](#l39.119)
- }
+#endif + sock = PyLong_FromSocket_t(newfd); if (sock == NULL) { SOCKETCLOSE(newfd); @@ -3909,6 +3938,12 @@ sock_new(PyTypeObject *type, PyObject a / Initialize a new socket object. / +#ifdef SOCK_CLOEXEC +/ socket() and socketpair() fail with EINVAL on Linux kernel older
- than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */ +static int sock_cloexec_works = -1; +#endif + /ARGSUSED/ static int sock_initobj(PyObject *self, PyObject *args, PyObject *kwds) @@ -3918,6 +3953,13 @@ sock_initobj(PyObject *self, PyObject *a SOCKET_T fd = INVALID_SOCKET; int family = AF_INET, type = SOCK_STREAM, proto = 0; static char *keywords[] = {"family", "type", "proto", "fileno", 0}; +#ifndef MS_WINDOWS +#ifdef SOCK_CLOEXEC
- int *atomic_flag_works = &sock_cloexec_works;
+#endif +#endif if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiiO:socket", keywords, @@ -3962,14 +4004,74 @@ sock_initobj(PyObject *self, PyObject *a } } else { +#ifdef MS_WINDOWS
/* Windows implementation */[](#l39.158)
+#ifndef WSA_FLAG_NO_HANDLE_INHERIT +#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 +#endif + Py_BEGIN_ALLOW_THREADS
fd = socket(family, type, proto);[](#l39.164)
if (support_wsa_no_inherit) {[](#l39.165)
fd = WSASocket(family, type, proto,[](#l39.166)
NULL, 0,[](#l39.167)
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);[](#l39.168)
if (fd == INVALID_SOCKET) {[](#l39.169)
/* Windows 7 or Windows 2008 R2 without SP1 or the hotfix */[](#l39.170)
support_wsa_no_inherit = 0;[](#l39.171)
fd = socket(family, type, proto);[](#l39.172)
}[](#l39.173)
}[](#l39.174)
else {[](#l39.175)
fd = socket(family, type, proto);[](#l39.176)
}[](#l39.177) Py_END_ALLOW_THREADS[](#l39.178)
if (fd == INVALID_SOCKET) { set_error(); return -1; } +
if (!support_wsa_no_inherit) {[](#l39.185)
if (!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0)) {[](#l39.186)
closesocket(fd);[](#l39.187)
PyErr_SetFromWindowsErr(0);[](#l39.188)
return -1;[](#l39.189)
}[](#l39.190)
}[](#l39.191)
/* UNIX */[](#l39.193)
Py_BEGIN_ALLOW_THREADS[](#l39.194)
if (sock_cloexec_works != 0) {[](#l39.196)
fd = socket(family, type | SOCK_CLOEXEC, proto);[](#l39.197)
if (sock_cloexec_works == -1) {[](#l39.198)
if (fd >= 0) {[](#l39.199)
sock_cloexec_works = 1;[](#l39.200)
}[](#l39.201)
else if (errno == EINVAL) {[](#l39.202)
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */[](#l39.203)
sock_cloexec_works = 0;[](#l39.204)
fd = socket(family, type, proto);[](#l39.205)
}[](#l39.206)
}[](#l39.207)
}[](#l39.208)
else[](#l39.209)
{[](#l39.211)
fd = socket(family, type, proto);[](#l39.212)
}[](#l39.213)
Py_END_ALLOW_THREADS[](#l39.214)
if (fd == INVALID_SOCKET) {[](#l39.216)
set_error();[](#l39.217)
return -1;[](#l39.218)
}[](#l39.219)
if (_Py_set_inheritable(fd, 0, atomic_flag_works) < 0) {[](#l39.221)
SOCKETCLOSE(fd);[](#l39.222)
return -1;[](#l39.223)
}[](#l39.224)
+#endif } init_sockobject(s, fd, family, type, proto); @@ -4535,16 +4637,36 @@ socket_dup(PyObject *self, PyObject *fdo { SOCKET_T fd, newfd; PyObject *newfdobj; - +#ifdef MS_WINDOWS
+#endif fd = PyLong_AsSocket_t(fdobj); if (fd == (SOCKET_T)(-1) && PyErr_Occurred()) return NULL;
- newfd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,[](#l39.248)
if (newfd == INVALID_SOCKET) return set_error();&info, 0, WSA_FLAG_OVERLAPPED);[](#l39.249)
- if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) {
closesocket(newfd);[](#l39.254)
PyErr_SetFromWindowsErr(0);[](#l39.255)
return NULL;[](#l39.256)
- }
- /* On UNIX, dup can be used to duplicate the file descriptor of a socket */
- newfd = _Py_dup(fd);
- if (newfd == INVALID_SOCKET)
return NULL; [](#l39.262)
+#endif + newfdobj = PyLong_FromSocket_t(newfd); if (newfdobj == NULL) SOCKETCLOSE(newfd); @@ -4572,6 +4694,12 @@ socket_socketpair(PyObject *self, PyObje SOCKET_T sv[2]; int family, type = SOCK_STREAM, proto = 0; PyObject *res = NULL; +#ifdef SOCK_CLOEXEC
#if defined(AF_UNIX) family = AF_UNIX; @@ -4581,9 +4709,38 @@ socket_socketpair(PyObject self, PyObje if (!PyArg_ParseTuple(args, "|iii:socketpair", &family, &type, &proto)) return NULL; + / Create a pair of socket fds */
- if (sock_cloexec_works != 0) {
ret = socketpair(family, type | SOCK_CLOEXEC, proto, sv);[](#l39.291)
if (sock_cloexec_works == -1) {[](#l39.292)
if (ret >= 0) {[](#l39.293)
sock_cloexec_works = 1;[](#l39.294)
}[](#l39.295)
else if (errno == EINVAL) {[](#l39.296)
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */[](#l39.297)
sock_cloexec_works = 0;[](#l39.298)
ret = socketpair(family, type, proto, sv);[](#l39.299)
}[](#l39.300)
}[](#l39.301)
- }
- else
- if (_Py_set_inheritable(sv[0], 0, atomic_flag_works) < 0)
goto finally;[](#l39.314)
- if (_Py_set_inheritable(sv[1], 0, atomic_flag_works) < 0)
goto finally;[](#l39.316)
+ s0 = new_sockobject(sv[0], family, type, proto); if (s0 == NULL) goto finally; @@ -4605,7 +4762,7 @@ finally: } PyDoc_STRVAR(socketpair_doc, -"socketpair([family[, type[, proto]]]) -> (socket object, socket object)\n[](#l39.325) +"socketpair([family[, type [, proto]]]) -> (socket object, socket object)\n[](#l39.326) \n[](#l39.327) Create a pair of socket objects from the sockets returned by the platform\n[](#l39.328) socketpair() function.\n[](#l39.329) @@ -5539,6 +5696,16 @@ PyInit__socket(void) if (!os_init()) return NULL; +#ifdef MS_WINDOWS
- if (support_wsa_no_inherit == -1) {
DWORD version = GetVersion();[](#l39.336)
DWORD major = (DWORD)LOBYTE(LOWORD(version));[](#l39.337)
DWORD minor = (DWORD)HIBYTE(LOWORD(version));[](#l39.338)
/* need Windows 7 SP1, 2008 R2 SP1 or later */[](#l39.339)
support_wsa_no_inherit = (major >= 6 && minor >= 1);[](#l39.340)
- }
+#endif + Py_TYPE(&sock_type) = &PyType_Type; m = PyModule_Create(&socketmodule); if (m == NULL)
--- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -870,7 +870,7 @@ read_directory(PyObject *archive) const char *charset; int bootstrap;
- fp = _Py_fopen_obj(archive, "rb"); if (fp == NULL) { if (!PyErr_Occurred()) PyErr_Format(ZipImportError, "can't open Zip file: %R", archive);
@@ -1064,7 +1064,7 @@ get_data(PyObject *archive, PyObject *to return NULL; }
--- a/PC/_msi.c +++ b/PC/_msi.c @@ -55,7 +55,7 @@ static FNFCIFREE(cb_free) static FNFCIOPEN(cb_open) {
- int result = _open(pszFile, oflag | O_NOINHERIT, pmode); if (result == -1) *err = errno; return result; @@ -179,7 +179,7 @@ static FNFCIGETOPENINFO(cb_getopeninfo) CloseHandle(handle);
} static PyObject* fcicreate(PyObject* obj, PyObject* args)
--- a/PC/bdist_wininst/install.c +++ b/PC/bdist_wininst/install.c @@ -743,7 +743,7 @@ do_run_installscript(HINSTANCE hPython, if (pathname == NULL || pathname[0] == '\0') return 2;
- fh = open(pathname, _O_RDONLY | O_NOINHERIT); if (-1 == fh) { fprintf(stderr, "Could not open postinstall-script %s\n", pathname);
--- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1730,10 +1730,15 @@ PyTokenizer_FindEncodingFilename(int fd, FILE *fp; char *p_start =NULL , *p_end =NULL , *encoding = NULL; +#ifndef PGEN
+#else fd = dup(fd); +#endif if (fd < 0) { return NULL; } + fp = fdopen(fd, "r"); if (fp == NULL) { return NULL;
--- a/Python/errors.c +++ b/Python/errors.c @@ -1042,7 +1042,7 @@ PyErr_ProgramText(const char *filename, FILE *fp; if (filename == NULL || *filename == '\0' || lineno <= 0) return NULL;
@@ -1052,7 +1052,7 @@ PyErr_ProgramTextObject(PyObject *filena FILE *fp; if (filename == NULL || lineno <= 0) return NULL;
--- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -9,10 +9,29 @@ #include <langinfo.h> #endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif /* HAVE_FCNTL_H / + #ifdef APPLE extern wchar_t _Py_DecodeUTF8_surrogateescape(const char s, Py_ssize_t size); #endif +#ifdef O_CLOEXEC +/ Does open() supports the O_CLOEXEC flag? Possible values: +
- -1: unknown
- 0: open() ignores O_CLOEXEC flag, ex: Linux kernel older than 2.6.23
- 1: open() supports O_CLOEXEC flag, close-on-exec is set
- The flag is used by _Py_open(), io.FileIO and os.open() */ +int _Py_open_cloexec_works = -1; +#endif +
PyObject * _Py_device_encoding(int fd) { @@ -547,14 +566,215 @@ int #endif +int +get_inheritable(int fd, int raise) +{ +#ifdef MS_WINDOWS
- if (!_PyVerify_fd(fd)) {
if (raise)[](#l45.45)
PyErr_SetFromErrno(PyExc_OSError);[](#l45.46)
return -1;[](#l45.47)
- }
- handle = (HANDLE)_get_osfhandle(fd);
- if (handle == INVALID_HANDLE_VALUE) {
if (raise)[](#l45.52)
PyErr_SetFromWindowsErr(0);[](#l45.53)
return -1;[](#l45.54)
- }
- if (!GetHandleInformation(handle, &flags)) {
if (raise)[](#l45.58)
PyErr_SetFromWindowsErr(0);[](#l45.59)
return -1;[](#l45.60)
- }
- flags = fcntl(fd, F_GETFD, 0);
- if (flags == -1) {
if (raise)[](#l45.69)
PyErr_SetFromErrno(PyExc_OSError);[](#l45.70)
return -1;[](#l45.71)
- }
- return !(flags & FD_CLOEXEC);
+#endif +} + +/* Get the inheritable flag of the specified file descriptor.
- Return 1 if it the file descriptor can be inherited, 0 if it cannot,
- raise an exception and return -1 on error. */ +int +_Py_get_inheritable(int fd) +{
- return get_inheritable(fd, 1);
+} + +static int +set_inheritable(int fd, int inheritable, int raise, int *atomic_flag_works) +{ +#ifdef MS_WINDOWS
+#elif defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)
- /* atomic_flag_works can only be used to make the file descriptor
non-inheritable */[](#l45.101)
- assert(!(atomic_flag_works != NULL && inheritable));
- if (atomic_flag_works != NULL && !inheritable) {
if (*atomic_flag_works == -1) {[](#l45.105)
int inheritable = get_inheritable(fd, raise);[](#l45.106)
if (inheritable == -1)[](#l45.107)
return -1;[](#l45.108)
*atomic_flag_works = !inheritable;[](#l45.109)
}[](#l45.110)
- if (!_PyVerify_fd(fd)) {
if (raise)[](#l45.118)
PyErr_SetFromErrno(PyExc_OSError);[](#l45.119)
return -1;[](#l45.120)
- }
- handle = (HANDLE)_get_osfhandle(fd);
- if (handle == INVALID_HANDLE_VALUE) {
if (raise)[](#l45.125)
PyErr_SetFromWindowsErr(0);[](#l45.126)
return -1;[](#l45.127)
- }
- if (inheritable)
flags = HANDLE_FLAG_INHERIT;[](#l45.131)
- else
flags = 0;[](#l45.133)
- if (!SetHandleInformation(handle, HANDLE_FLAG_INHERIT, flags)) {
if (raise)[](#l45.135)
PyErr_SetFromWindowsErr(0);[](#l45.136)
return -1;[](#l45.137)
- }
- return 0;
+ +#elif defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)
- if (inheritable)
request = FIONCLEX;[](#l45.143)
- else
request = FIOCLEX;[](#l45.145)
- err = ioctl(fd, request);
- if (err) {
if (raise)[](#l45.148)
PyErr_SetFromErrno(PyExc_OSError);[](#l45.149)
return -1;[](#l45.150)
- }
- return 0;
- flags = fcntl(fd, F_GETFD);
- if (flags < 0) {
if (raise)[](#l45.157)
PyErr_SetFromErrno(PyExc_OSError);[](#l45.158)
return -1;[](#l45.159)
- }
- if (inheritable)
flags &= ~FD_CLOEXEC;[](#l45.163)
- else
flags |= FD_CLOEXEC;[](#l45.165)
- res = fcntl(fd, F_SETFD, flags);
- if (res < 0) {
if (raise)[](#l45.168)
PyErr_SetFromErrno(PyExc_OSError);[](#l45.169)
return -1;[](#l45.170)
- }
- return 0;
+#endif +} + +/* Make the file descriptor non-inheritable.
- Return 0 success, set errno and return -1 on error. */ +static int +make_non_inheritable(int fd) +{
- return set_inheritable(fd, 0, 0, NULL);
+} + +/* Set the inheritable flag of the specified file descriptor.
- On success: return 0, on error: raise an exception if raise is nonzero
- and return -1. +
- If atomic_flag_works is not NULL: +
descriptor: if yes, set *atomic_flag_works to 1, otherwise set to 0 and[](#l45.191)
set the inheritable flag[](#l45.192)
- Set atomic_flag_works to NULL if no atomic flag was used to create the
- file descriptor. +
- atomic_flag_works can only be used to make a file descriptor
- non-inheritable: atomic_flag_works must be NULL if inheritable=1. */ +int +_Py_set_inheritable(int fd, int inheritable, int *atomic_flag_works) +{
- return set_inheritable(fd, inheritable, 1, atomic_flag_works);
+} + +/* Open a file with the specified flags (wrapper to open() function).
- The file descriptor is created non-inheritable. */ +int +_Py_open(const char *pathname, int flags) +{
- int fd;
- if (set_inheritable(fd, 0, 0, atomic_flag_works) < 0) {
close(fd);[](#l45.231)
return -1;[](#l45.232)
- }
+} + /* Open a file. Use _wfopen() on Windows, encode the path to the locale
- encoding and use fopen() otherwise. The file descriptor is created
- non-inheritable. */ FILE * _Py_wfopen(const wchar_t *path, const wchar_t *mode) {
- FILE *f;
- FILE *f; char *cpath; char cmode[10]; size_t r; @@ -568,21 +788,42 @@ FILE * return NULL; f = fopen(cpath, cmode); PyMem_Free(cpath); +#else
- if (f == NULL)
return NULL;[](#l45.260)
- if (make_non_inheritable(fileno(f)) < 0) {
fclose(f);[](#l45.262)
return NULL;[](#l45.263)
- } return f; -#else
-#endif } -/* Call _wfopen() on Windows, or encode the path to the filesystem encoding and
- call fopen() otherwise. +/* Wrapper to fopen(). The file descriptor is created non-inheritable. / +FILE +_Py_fopen(const char *pathname, const char *mode) +{
- FILE *f = fopen(pathname, mode);
- if (f == NULL)
return NULL;[](#l45.279)
- if (make_non_inheritable(fileno(f)) < 0) {
fclose(f);[](#l45.281)
return NULL;[](#l45.282)
- }
- return f;
+} + +/* Open a file. Call _wfopen() on Windows, or encode the path to the filesystem
- encoding and call fopen() otherwise. The file descriptor is created
- non-inheritable. Return the new file object on success, or NULL if the file cannot be open or
- (if PyErr_Occurred()) on unicode error. / FILE -_Py_fopen(PyObject *path, const char *mode) +_Py_fopen_obj(PyObject *path, const char *mode) {
- FILE *f;
#ifdef MS_WINDOWS wchar_t wpath; wchar_t wmode[10]; @@ -602,16 +843,21 @@ FILE if (usize == 0) return NULL;
- FILE *f; PyObject *bytes; if (!PyUnicode_FSConverter(path, &bytes)) return NULL; f = fopen(PyBytes_AS_STRING(bytes), mode); Py_DECREF(bytes); +#endif
- if (f == NULL)
return NULL;[](#l45.318)
- if (make_non_inheritable(fileno(f)) < 0) {
fclose(f);[](#l45.320)
return NULL;[](#l45.321)
- } return f; -#endif }
#ifdef HAVE_READLINK @@ -729,3 +975,72 @@ wchar_t* #endif } +/* Duplicate a file descriptor. The new file descriptor is created as
- non-inheritable. Return a new file descriptor on success, raise an OSError
- exception and return -1 on error. +
- The GIL is released to call dup(). The caller must hold the GIL. */ +int +_Py_dup(int fd) +{ +#ifdef MS_WINDOWS
- HANDLE handle;
- DWORD ftype;
- handle = (HANDLE)_get_osfhandle(fd);
- if (handle == INVALID_HANDLE_VALUE) {
PyErr_SetFromWindowsErr(0);[](#l45.353)
return -1;[](#l45.354)
- }
- Py_BEGIN_ALLOW_THREADS
- fd = dup(fd);
- Py_END_ALLOW_THREADS
- if (fd < 0) {
PyErr_SetFromErrno(PyExc_OSError);[](#l45.364)
return -1;[](#l45.365)
- }
- /* Character files like console cannot be make non-inheritable */
- if (ftype != FILE_TYPE_CHAR) {
if (_Py_set_inheritable(fd, 0, NULL) < 0) {[](#l45.370)
close(fd);[](#l45.371)
return -1;[](#l45.372)
}[](#l45.373)
- }
+#elif defined(HAVE_FCNTL_H) && defined(F_DUPFD_CLOEXEC)
- Py_BEGIN_ALLOW_THREADS
- fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
- Py_END_ALLOW_THREADS
- if (fd < 0) {
PyErr_SetFromErrno(PyExc_OSError);[](#l45.380)
return -1;[](#l45.381)
- }
- Py_BEGIN_ALLOW_THREADS
- fd = dup(fd);
- Py_END_ALLOW_THREADS
- if (fd < 0) {
PyErr_SetFromErrno(PyExc_OSError);[](#l45.389)
return -1;[](#l45.390)
- }
--- a/Python/import.c +++ b/Python/import.c @@ -1797,7 +1797,7 @@ imp_load_dynamic(PyObject *self, PyObjec &name, PyUnicode_FSDecoder, &pathname, &fob)) return NULL; if (fob != NULL) {
fp = _Py_fopen(pathname, "r");[](#l46.7)
fp = _Py_fopen_obj(pathname, "r");[](#l46.8) if (fp == NULL) {[](#l46.9) Py_DECREF(pathname);[](#l46.10) if (!PyErr_Occurred())[](#l46.11)
--- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1454,7 +1454,7 @@ PyRun_SimpleFileExFlags(FILE fp, const / Try to run a pyc file. First, re-open in binary */ if (closeit) fclose(fp);
if ((pyc_fp = fopen(filename, "rb")) == NULL) {[](#l47.7)
if ((pyc_fp = _Py_fopen(filename, "rb")) == NULL) {[](#l47.8) fprintf(stderr, "python: Can't reopen .pyc file\n");[](#l47.9) goto done;[](#l47.10) }[](#l47.11)
--- a/Python/random.c +++ b/Python/random.c @@ -101,7 +101,7 @@ dev_urandom_noraise(char *buffer, Py_ssi assert (0 < size);
@@ -134,7 +134,7 @@ dev_urandom_python(char *buffer, Py_ssiz return 0; Py_BEGIN_ALLOW_THREADS
--- a/configure +++ b/configure @@ -10275,7 +10275,7 @@ fi
checks for library functions
for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown [](#l49.6)
- clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat [](#l49.7)
- clock confstr ctermid dup3 execv faccessat fchmod fchmodat fchown fchownat [](#l49.8) fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat [](#l49.9) futimens futimes gai_strerror [](#l49.10) getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid [](#l49.11)
--- a/configure.ac +++ b/configure.ac @@ -2807,7 +2807,7 @@ fi
checks for library functions
AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown [](#l50.6)
- clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat [](#l50.7)
- clock confstr ctermid dup3 execv faccessat fchmod fchmodat fchown fchownat [](#l50.8) fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat [](#l50.9) futimens futimes gai_strerror [](#l50.10) getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid [](#l50.11)
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -193,6 +193,9 @@
/* Define to 1 if you have the dup2' function. */[](#l51.4) #undef HAVE_DUP2[](#l51.5) [](#l51.6) +/* Define to 1 if you have the
dup3' function. /
+#undef HAVE_DUP3
+
/ Defined when any dynamic module loading is enabled. */
#undef HAVE_DYNAMIC_LOADING