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().
This commit is contained in:
Victor Stinner 2013-08-28 00:53:59 +02:00
parent 46e1ce214b
commit daf455554b
51 changed files with 1448 additions and 317 deletions

View file

@ -979,6 +979,8 @@ are always available. They are listed here in alphabetical order.
:mod:`os.open` as *opener* results in functionality similar to passing :mod:`os.open` as *opener* results in functionality similar to passing
``None``). ``None``).
The newly created file is :ref:`non-inheritable <fd_inheritance>`.
The following example uses the :ref:`dir_fd <dir_fd>` parameter of the 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:: :func:`os.open` function to open a file relative to a given directory::
@ -992,10 +994,6 @@ are always available. They are listed here in alphabetical order.
... ...
>>> os.close(dir_fd) # don't leak a file descriptor >>> os.close(dir_fd) # don't leak a file descriptor
.. versionchanged:: 3.3
The *opener* parameter was added.
The ``'x'`` mode was added.
The type of :term:`file object` returned by the :func:`open` function 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 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 mode (``'w'``, ``'r'``, ``'wt'``, ``'rt'``, etc.), it returns a subclass of
@ -1022,10 +1020,15 @@ are always available. They are listed here in alphabetical order.
and :mod:`shutil`. and :mod:`shutil`.
.. versionchanged:: 3.3 .. versionchanged:: 3.3
The *opener* parameter was added.
The ``'x'`` mode was added.
:exc:`IOError` used to be raised, it is now an alias of :exc:`OSError`. :exc:`IOError` used to be raised, it is now an alias of :exc:`OSError`.
:exc:`FileExistsError` is now raised if the file opened in exclusive :exc:`FileExistsError` is now raised if the file opened in exclusive
creation mode (``'x'``) already exists. creation mode (``'x'``) already exists.
.. versionchanged:: 3.4
The file is now non-inheritable.
.. XXX works for bytes too, but should it? .. XXX works for bytes too, but should it?
.. function:: ord(c) .. function:: ord(c)

View file

@ -522,6 +522,8 @@ Raw File I/O
:mod:`os.open` as *opener* results in functionality similar to passing :mod:`os.open` as *opener* results in functionality similar to passing
``None``). ``None``).
The newly created file is :ref:`non-inheritable <fd_inheritance>`.
See the :func:`open` built-in function for examples on using the *opener* See the :func:`open` built-in function for examples on using the *opener*
parameter. parameter.
@ -529,6 +531,9 @@ Raw File I/O
The *opener* parameter was added. The *opener* parameter was added.
The ``'x'`` mode was added. The ``'x'`` mode was added.
.. versionchanged:: 3.4
The file is now non-inheritable.
In addition to the attributes and methods from :class:`IOBase` and In addition to the attributes and methods from :class:`IOBase` and
:class:`RawIOBase`, :class:`FileIO` provides the following data :class:`RawIOBase`, :class:`FileIO` provides the following data
attributes: attributes:

View file

@ -685,17 +685,30 @@ as internal buffering of data.
.. function:: dup(fd) .. function:: dup(fd)
Return a duplicate of file descriptor *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
<fd_inheritance>`.
Availability: Unix, Windows. Availability: Unix, Windows.
.. versionchanged:: 3.4
The new file descriptor is now non-inheritable.
.. function:: dup2(fd, fd2)
.. function:: dup2(fd, fd2, inheritable=True)
Duplicate file descriptor *fd* to *fd2*, closing the latter first if necessary. 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. Availability: Unix, Windows.
.. versionchanged:: 3.4
Add the optional *inheritable* parameter.
.. function:: fchmod(fd, mode) .. 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 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 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. 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; 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 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. Availability: Unix, Windows.
.. versionchanged:: 3.4
The new file descriptor is now non-inheritable.
.. note:: .. note::
This function is intended for low-level I/O. For normal usage, use the 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/en-us/library/z0kc8e3z.aspx>`_ on Window
.. index:: module: pty .. index:: module: pty
Open a new pseudo-terminal pair. Return a pair of file descriptors ``(master, Open a new pseudo-terminal pair. Return a pair of file descriptors
slave)`` for the pty and the tty, respectively. For a (slightly) more portable ``(master, slave)`` for the pty and the tty, respectively. The new file
approach, use the :mod:`pty` module. descriptors are :ref:`non-inheritable <fd_inheritance>`. For a (slightly) more
portable approach, use the :mod:`pty` module.
Availability: some flavors of Unix. Availability: some flavors of Unix.
.. versionchanged:: 3.4
The new file descriptors are now non-inheritable.
.. function:: pipe() .. function:: pipe()
Create a pipe. Return a pair of file descriptors ``(r, w)`` usable for reading Create a pipe. Return a pair of file descriptors ``(r, w)`` usable for
and writing, respectively. reading and writing, respectively. The new file descriptor are
:ref:`non-inheritable <fd_inheritance>`.
Availability: Unix, Windows. Availability: Unix, Windows.
.. versionchanged:: 3.4
The new file descriptors are now non-inheritable.
.. function:: pipe2(flags) .. function:: pipe2(flags)
@ -1178,6 +1203,50 @@ Querying the size of a terminal
Height of the terminal window in characters. 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)
Set the `inheritable flag <fd_inheritance>`_ of the specified file descriptor.
.. 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)
Set the `inheritable flag <fd_inheritance>`_ of the specified handle.
Availability: Windows.
.. _os-file-dir: .. _os-file-dir:
Files and Directories Files and Directories

View file

@ -37,8 +37,13 @@ The module defines the following:
increases this value, :c:func:`devpoll` may return an increases this value, :c:func:`devpoll` may return an
incomplete list of active file descriptors. incomplete list of active file descriptors.
The new file descriptor is :ref:`non-inheritable <fd_inheritance>`.
.. versionadded:: 3.3 .. versionadded:: 3.3
.. versionchanged:: 3.4
The new file descriptor is now non-inheritable.
.. function:: epoll(sizehint=-1, flags=0) .. function:: epoll(sizehint=-1, flags=0)
(Only supported on Linux 2.5.44 and newer.) Return an edge polling object, (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. :ref:`epoll-objects` below for the methods supported by epolling objects.
They also support the :keyword:`with` statement. They also support the :keyword:`with` statement.
The new file descriptor is :ref:`non-inheritable <fd_inheritance>`.
.. versionchanged:: 3.3 .. versionchanged:: 3.3
Added the *flags* parameter. Added the *flags* parameter.
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Support for the :keyword:`with` statement was added. Support for the :keyword:`with` statement was added.
The new file descriptor is now non-inheritable.
.. function:: poll() .. function:: poll()
@ -69,6 +77,11 @@ The module defines the following:
(Only supported on BSD.) Returns a kernel queue object; see section (Only supported on BSD.) Returns a kernel queue object; see section
:ref:`kqueue-objects` below for the methods supported by kqueue objects. :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.
.. function:: kevent(ident, filter=KQ_FILTER_READ, flags=KQ_EV_ADD, fflags=0, data=0, udata=0) .. function:: kevent(ident, filter=KQ_FILTER_READ, flags=KQ_EV_ADD, fflags=0, data=0, udata=0)

View file

@ -460,7 +460,7 @@ The module :mod:`socket` exports the following constants and functions:
``'udp'``, otherwise any protocol will match. ``'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 Create a new socket using the given address family, socket type and protocol
number. The address family should be :const:`AF_INET` (the default), number. The address family should be :const:`AF_INET` (the default),
@ -471,12 +471,18 @@ The module :mod:`socket` exports the following constants and functions:
case where the address family is :const:`AF_CAN` the protocol should be one case where the address family is :const:`AF_CAN` the protocol should be one
of :const:`CAN_RAW` or :const:`CAN_BCM`. of :const:`CAN_RAW` or :const:`CAN_BCM`.
The newly created socket is :ref:`non-inheritable <fd_inheritance>`.
.. versionchanged:: 3.3 .. versionchanged:: 3.3
The AF_CAN family was added. The AF_CAN family was added.
The AF_RDS family was added. The AF_RDS family was added.
.. versionchanged:: 3.4 .. versionchanged:: 3.4
The CAN_BCM protocol was added. The CAN_BCM protocol was added.
.. versionchanged:: 3.4
The socket is now non-inheritable.
.. function:: socketpair([family[, type[, proto]]]) .. function:: socketpair([family[, type[, proto]]])
@ -486,12 +492,17 @@ The module :mod:`socket` exports the following constants and functions:
if defined on the platform; otherwise, the default is :const:`AF_INET`. if defined on the platform; otherwise, the default is :const:`AF_INET`.
Availability: Unix. Availability: Unix.
The newly created sockets are :ref:`non-inheritable <fd_inheritance>`.
.. versionchanged:: 3.2 .. versionchanged:: 3.2
The returned socket objects now support the whole socket API, rather The returned socket objects now support the whole socket API, rather
than a subset. than a subset.
.. versionchanged:: 3.4
The sockets are now non-inheritable.
.. 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 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 :meth:`fileno` method) and build a socket object from the result. Address
@ -502,6 +513,11 @@ The module :mod:`socket` exports the following constants and functions:
a socket passed to a program as standard input or output (such as a server 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. 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.
.. function:: ntohl(x) .. function:: ntohl(x)
@ -730,6 +746,11 @@ correspond to Unix system calls applicable to sockets.
*new* socket object usable to send and receive data on the connection, and *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. *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.
.. method:: socket.bind(address) .. method:: socket.bind(address)
@ -775,6 +796,16 @@ correspond to Unix system calls applicable to sockets.
.. versionadded:: 3.2 .. 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.
.. method:: socket.fileno() .. method:: socket.fileno()
Return the socket's file descriptor (a small integer). This is useful with Return the socket's file descriptor (a small integer). This is useful with
@ -785,6 +816,15 @@ correspond to Unix system calls applicable to sockets.
this limitation. 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() .. method:: socket.getpeername()
Return the remote address to which the socket is connected. This is useful to Return the remote address to which the socket is connected. This is useful to
@ -1068,6 +1108,14 @@ correspond to Unix system calls applicable to sockets.
.. versionadded:: 3.3 .. 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) .. method:: socket.setblocking(flag)
Set blocking or non-blocking mode of the socket: if *flag* is false, the Set blocking or non-blocking mode of the socket: if *flag* is false, the

View file

@ -96,6 +96,7 @@ New built-in features:
* :ref:`PEP 442: Safe object finalization <pep-442>`. * :ref:`PEP 442: Safe object finalization <pep-442>`.
* :ref:`PEP 445: Configurable memory allocators <pep-445>`. * :ref:`PEP 445: Configurable memory allocators <pep-445>`.
* :ref:`PEP 446: Make newly created file descriptors non-inheritable <pep-446>`.
Implementation improvements: Implementation improvements:
@ -118,6 +119,19 @@ Security improvements:
Please read on for a comprehensive list of user-facing changes. 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 descriptors `non-inheritable
<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:
PEP 445: Add new APIs to customize Python memory allocators PEP 445: Add new APIs to customize Python memory allocators
@ -267,6 +281,16 @@ Also, except when using the old *fork* start method, child processes
will no longer inherit unneeded handles/file descriptors from their parents. will no longer inherit unneeded handles/file descriptors from their parents.
os
--
New functions to get and set the `inheritable 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 poplib
------ ------
@ -288,6 +312,15 @@ try/except statement by code that only cares whether or not an error occurred.
(:issue:`2118`). (:issue:`2118`).
socket
------
Socket objects have new methods to get or set their `inheritable flag
<fd_inheritance>`_:
* :meth:`socket.socket.get_inheritable`, :meth:`socket.socket.set_inheritable`
ssl ssl
--- ---

View file

@ -27,11 +27,19 @@ PyAPI_FUNC(int) _Py_stat(
struct stat *statbuf); struct stat *statbuf);
#endif #endif
PyAPI_FUNC(int) _Py_open(
const char *pathname,
int flags);
PyAPI_FUNC(FILE *) _Py_wfopen( PyAPI_FUNC(FILE *) _Py_wfopen(
const wchar_t *path, const wchar_t *path,
const wchar_t *mode); const wchar_t *mode);
PyAPI_FUNC(FILE*) _Py_fopen( PyAPI_FUNC(FILE*) _Py_fopen(
const char *pathname,
const char *mode);
PyAPI_FUNC(FILE*) _Py_fopen_obj(
PyObject *path, PyObject *path,
const char *mode); const char *mode);
@ -53,6 +61,13 @@ PyAPI_FUNC(wchar_t*) _Py_wgetcwd(
wchar_t *buf, wchar_t *buf,
size_t size); 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);
PyAPI_FUNC(int) _Py_dup(int fd);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -129,6 +129,8 @@ def open(file, mode="r", buffering=-1, encoding=None, errors=None,
be kept open when the file is closed. This does not work when a file name is 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. given and must be True in that case.
The newly created file is non-inheritable.
A custom opener can be used by passing a callable as *opener*. The 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 underlying file descriptor for the file object is then obtained by calling
*opener* with (*file*, *flags*). *opener* must return an open file *opener* with (*file*, *flags*). *opener* must return an open file

View file

@ -509,7 +509,7 @@ if sys.platform != 'win32':
c1 = Connection(s1.detach()) c1 = Connection(s1.detach())
c2 = Connection(s2.detach()) c2 = Connection(s2.detach())
else: else:
fd1, fd2 = util.pipe() fd1, fd2 = os.pipe()
c1 = Connection(fd1, writable=False) c1 = Connection(fd1, writable=False)
c2 = Connection(fd2, readable=False) c2 = Connection(fd2, readable=False)
@ -536,7 +536,9 @@ else:
_winapi.FILE_FLAG_FIRST_PIPE_INSTANCE, _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE,
_winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE | _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE |
_winapi.PIPE_WAIT, _winapi.PIPE_WAIT,
1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL 1, obsize, ibsize, _winapi.NMPWAIT_WAIT_FOREVER,
# default security descriptor: the handle cannot be inherited
_winapi.NULL
) )
h2 = _winapi.CreateFile( h2 = _winapi.CreateFile(
address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING, address, access, 0, _winapi.NULL, _winapi.OPEN_EXISTING,

View file

@ -60,8 +60,8 @@ def connect_to_new_process(fds):
raise ValueError('too many fds') raise ValueError('too many fds')
with socket.socket(socket.AF_UNIX) as client: with socket.socket(socket.AF_UNIX) as client:
client.connect(_forkserver_address) client.connect(_forkserver_address)
parent_r, child_w = util.pipe() parent_r, child_w = os.pipe()
child_r, parent_w = util.pipe() child_r, parent_w = os.pipe()
allfds = [child_r, child_w, _forkserver_alive_fd, allfds = [child_r, child_w, _forkserver_alive_fd,
semaphore_tracker._semaphore_tracker_fd] semaphore_tracker._semaphore_tracker_fd]
allfds += fds allfds += fds

View file

@ -66,7 +66,7 @@ class Popen(object):
def _launch(self, process_obj): def _launch(self, process_obj):
code = 1 code = 1
parent_r, child_w = util.pipe() parent_r, child_w = os.pipe()
self.pid = os.fork() self.pid = os.fork()
if self.pid == 0: if self.pid == 0:
try: try:

View file

@ -54,8 +54,8 @@ class Popen(popen_fork.Popen):
parent_r = child_w = child_r = parent_w = None parent_r = child_w = child_r = parent_w = None
try: try:
parent_r, child_w = util.pipe() parent_r, child_w = os.pipe()
child_r, parent_w = util.pipe() child_r, parent_w = os.pipe()
cmd = spawn.get_command_line(tracker_fd=tracker_fd, cmd = spawn.get_command_line(tracker_fd=tracker_fd,
pipe_handle=child_r) pipe_handle=child_r)
self._fds.extend([child_r, child_w]) self._fds.extend([child_r, child_w])

View file

@ -45,7 +45,7 @@ def ensure_running():
except Exception: except Exception:
pass pass
cmd = 'from multiprocessing.semaphore_tracker import main; main(%d)' cmd = 'from multiprocessing.semaphore_tracker import main; main(%d)'
r, w = util.pipe() r, w = os.pipe()
try: try:
fds_to_pass.append(r) fds_to_pass.append(r)
# process will out live us, so no need to wait on pid # process will out live us, so no need to wait on pid

View file

@ -365,7 +365,7 @@ def spawnv_passfds(path, args, passfds):
if flag & fcntl.FD_CLOEXEC: if flag & fcntl.FD_CLOEXEC:
fcntl.fcntl(fd, fcntl.F_SETFD, flag & ~fcntl.FD_CLOEXEC) fcntl.fcntl(fd, fcntl.F_SETFD, flag & ~fcntl.FD_CLOEXEC)
tmp.append((fd, flag)) tmp.append((fd, flag))
errpipe_read, errpipe_write = _posixsubprocess.cloexec_pipe() errpipe_read, errpipe_write = os.pipe()
try: try:
return _posixsubprocess.fork_exec( return _posixsubprocess.fork_exec(
args, [os.fsencode(path)], True, passfds, None, None, 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 # Return pipe with CLOEXEC set on fds
# #
# Deprecated: os.pipe() creates non-inheritable file descriptors
# since Python 3.4
#
def pipe(): def pipe():
import _posixsubprocess return os.pipe()
return _posixsubprocess.cloexec_pipe()

View file

@ -137,7 +137,8 @@ class socket(_socket.socket):
def dup(self): def dup(self):
"""dup() -> socket object """dup() -> socket object
Return a new socket object connected to the same system resource. Duplicate the socket. Return a new socket object connected to the same
system resource. The new socket is non-inheritable.
""" """
fd = dup(self.fileno()) fd = dup(self.fileno())
sock = self.__class__(self.family, self.type, self.proto, fileno=fd) sock = self.__class__(self.family, self.type, self.proto, fileno=fd)
@ -229,6 +230,20 @@ class socket(_socket.socket):
self._closed = True self._closed = True
return super().detach() return super().detach()
if os.name == 'nt':
def get_inheritable(self):
return os.get_handle_inheritable(self.fileno())
def set_inheritable(self, inheritable):
os.set_handle_inheritable(self.fileno(), inheritable)
else:
def get_inheritable(self):
return os.get_inheritable(self.fileno())
def set_inheritable(self, inheritable):
os.set_inheritable(self.fileno(), inheritable)
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): def fromfd(fd, family, type, proto=0):
""" fromfd(fd, family, type[, proto]) -> socket object """ fromfd(fd, family, type[, proto]) -> socket object

View file

@ -405,7 +405,6 @@ else:
import select import select
_has_poll = hasattr(select, 'poll') _has_poll = hasattr(select, 'poll')
import _posixsubprocess import _posixsubprocess
_create_pipe = _posixsubprocess.cloexec_pipe
# When select or poll has indicated that the file is writable, # When select or poll has indicated that the file is writable,
# we can write up to _PIPE_BUF bytes without risk of blocking. # we can write up to _PIPE_BUF bytes without risk of blocking.
@ -1258,7 +1257,7 @@ class Popen(object):
if stdin is None: if stdin is None:
pass pass
elif stdin == PIPE: elif stdin == PIPE:
p2cread, p2cwrite = _create_pipe() p2cread, p2cwrite = os.pipe()
elif stdin == DEVNULL: elif stdin == DEVNULL:
p2cread = self._get_devnull() p2cread = self._get_devnull()
elif isinstance(stdin, int): elif isinstance(stdin, int):
@ -1270,7 +1269,7 @@ class Popen(object):
if stdout is None: if stdout is None:
pass pass
elif stdout == PIPE: elif stdout == PIPE:
c2pread, c2pwrite = _create_pipe() c2pread, c2pwrite = os.pipe()
elif stdout == DEVNULL: elif stdout == DEVNULL:
c2pwrite = self._get_devnull() c2pwrite = self._get_devnull()
elif isinstance(stdout, int): elif isinstance(stdout, int):
@ -1282,7 +1281,7 @@ class Popen(object):
if stderr is None: if stderr is None:
pass pass
elif stderr == PIPE: elif stderr == PIPE:
errread, errwrite = _create_pipe() errread, errwrite = os.pipe()
elif stderr == STDOUT: elif stderr == STDOUT:
errwrite = c2pwrite errwrite = c2pwrite
elif stderr == DEVNULL: elif stderr == DEVNULL:
@ -1334,7 +1333,7 @@ class Popen(object):
# For transferring possible exec failure from child to parent. # For transferring possible exec failure from child to parent.
# Data format: "exception name:hex errno:description" # Data format: "exception name:hex errno:description"
# Pickle is not used; it is complex and involves memory allocation. # Pickle is not used; it is complex and involves memory allocation.
errpipe_read, errpipe_write = _create_pipe() errpipe_read, errpipe_write = os.pipe()
try: try:
try: try:
# We must avoid complex work that could involve # We must avoid complex work that could involve

View file

@ -34,23 +34,6 @@ import os as _os
import errno as _errno import errno as _errno
from random import Random as _Random from random import Random as _Random
try:
import fcntl as _fcntl
except ImportError:
def _set_cloexec(fd):
pass
else:
def _set_cloexec(fd):
try:
flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
except OSError:
pass
else:
# flags read successfully, modify
flags |= _fcntl.FD_CLOEXEC
_fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
try: try:
import _thread import _thread
except ImportError: except ImportError:
@ -58,10 +41,6 @@ except ImportError:
_allocate_lock = _thread.allocate_lock _allocate_lock = _thread.allocate_lock
_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL _text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
if hasattr(_os, 'O_CLOEXEC'):
_text_openflags |= _os.O_CLOEXEC
if hasattr(_os, 'O_NOINHERIT'):
_text_openflags |= _os.O_NOINHERIT
if hasattr(_os, 'O_NOFOLLOW'): if hasattr(_os, 'O_NOFOLLOW'):
_text_openflags |= _os.O_NOFOLLOW _text_openflags |= _os.O_NOFOLLOW
@ -90,8 +69,8 @@ else:
# Fallback. All we need is something that raises OSError if the # Fallback. All we need is something that raises OSError if the
# file doesn't exist. # file doesn't exist.
def _stat(fn): def _stat(fn):
f = open(fn) fd = _os.open(fn, _os.O_RDONLY)
f.close() os.close(fd)
def _exists(fn): def _exists(fn):
try: try:
@ -217,7 +196,6 @@ def _mkstemp_inner(dir, pre, suf, flags):
file = _os.path.join(dir, pre + name + suf) file = _os.path.join(dir, pre + name + suf)
try: try:
fd = _os.open(file, flags, 0o600) fd = _os.open(file, flags, 0o600)
_set_cloexec(fd)
return (fd, _os.path.abspath(file)) return (fd, _os.path.abspath(file))
except FileExistsError: except FileExistsError:
continue # try again continue # try again

View file

@ -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:
st = os.fstat(fd)
except OSError as e:
if e.errno == errno.EBADF:
continue
raise
# Ignore Solaris door files
if not stat.S_ISDOOR(st.st_mode):
inherited.append(fd)
print(','.join(map(str, inherited)))

View file

@ -744,7 +744,12 @@ class BaseTestAPI:
s.create_socket(self.family) s.create_socket(self.family)
self.assertEqual(s.socket.family, self.family) self.assertEqual(s.socket.family, self.family)
SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0) SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)
self.assertEqual(s.socket.type, socket.SOCK_STREAM | SOCK_NONBLOCK) sock_type = socket.SOCK_STREAM | SOCK_NONBLOCK
if hasattr(socket, 'SOCK_CLOEXEC'):
self.assertIn(s.socket.type,
(sock_type | socket.SOCK_CLOEXEC, sock_type))
else:
self.assertEqual(s.socket.type, sock_type)
def test_bind(self): def test_bind(self):
if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX: if HAS_UNIX_SOCKETS and self.family == socket.AF_UNIX:

View file

@ -1015,6 +1015,11 @@ class BuiltinTest(unittest.TestCase):
os.environ.clear() os.environ.clear()
os.environ.update(old_environ) os.environ.update(old_environ)
def test_open_non_inheritable(self):
fileobj = open(__file__)
with fileobj:
self.assertFalse(os.get_inheritable(fileobj.fileno()))
def test_ord(self): def test_ord(self):
self.assertEqual(ord(' '), 32) self.assertEqual(ord(' '), 32)
self.assertEqual(ord('A'), 65) self.assertEqual(ord('A'), 65)

View file

@ -2,7 +2,11 @@
# Initial tests are copied as is from "test_poll.py" # 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 from test.support import TESTFN, run_unittest
try: try:
@ -111,6 +115,11 @@ class DevPollTests(unittest.TestCase):
self.assertRaises(ValueError, devpoll.register, fd, fd, select.POLLIN) self.assertRaises(ValueError, devpoll.register, fd, fd, select.POLLIN)
self.assertRaises(ValueError, devpoll.unregister, fd) self.assertRaises(ValueError, devpoll.unregister, fd)
def test_fd_non_inheritable(self):
devpoll = select.devpoll()
self.addCleanup(devpoll.close)
self.assertEqual(os.get_inheritable(devpoll.fileno()), False)
def test_main(): def test_main():
run_unittest(DevPollTests) run_unittest(DevPollTests)

View file

@ -21,10 +21,11 @@
""" """
Tests for epoll wrapper. Tests for epoll wrapper.
""" """
import socket
import errno import errno
import time import os
import select import select
import socket
import time
import unittest import unittest
from test import support from test import support
@ -249,6 +250,11 @@ class TestEPoll(unittest.TestCase):
self.assertRaises(ValueError, epoll.register, fd, select.EPOLLIN) self.assertRaises(ValueError, epoll.register, fd, select.EPOLLIN)
self.assertRaises(ValueError, epoll.unregister, fd) self.assertRaises(ValueError, epoll.unregister, fd)
def test_fd_non_inheritable(self):
epoll = select.epoll()
self.addCleanup(epoll.close)
self.assertEqual(os.get_inheritable(epoll.fileno()), False)
def test_main(): def test_main():
support.run_unittest(TestEPoll) support.run_unittest(TestEPoll)

View file

@ -206,6 +206,11 @@ class TestKQueue(unittest.TestCase):
# operations must fail with ValueError("I/O operation on closed ...") # operations must fail with ValueError("I/O operation on closed ...")
self.assertRaises(ValueError, kqueue.control, None, 4) self.assertRaises(ValueError, kqueue.control, None, 4)
def test_fd_non_inheritable(self):
kqueue = select.kqueue()
self.addCleanup(kqueue.close)
self.assertEqual(os.get_inheritable(kqueue.fileno()), False)
def test_main(): def test_main():
support.run_unittest(TestKQueue) support.run_unittest(TestKQueue)

View file

@ -2298,6 +2298,72 @@ class CPUCountTests(unittest.TestCase):
else: else:
self.skipTest("Could not determine the number of CPUs") 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)
self.addCleanup(os.close, fd)
for inheritable in (False, True):
os.set_inheritable(fd, inheritable)
self.assertEqual(os.get_inheritable(fd), inheritable)
def test_set_inheritable(self):
fd = os.open(__file__, os.O_RDONLY)
self.addCleanup(os.close, fd)
os.set_inheritable(fd, True)
self.assertEqual(os.get_inheritable(fd), True)
def test_open(self):
fd = os.open(__file__, os.O_RDONLY)
self.addCleanup(os.close, fd)
self.assertEqual(os.get_inheritable(fd), False)
@unittest.skipUnless(hasattr(os, 'pipe'), "need os.pipe()")
def test_pipe(self):
rfd, wfd = os.pipe()
self.addCleanup(os.close, rfd)
self.addCleanup(os.close, wfd)
self.assertEqual(os.get_inheritable(rfd), False)
self.assertEqual(os.get_inheritable(wfd), False)
def test_dup(self):
fd1 = os.open(__file__, os.O_RDONLY)
self.addCleanup(os.close, fd1)
fd2 = os.dup(fd1)
self.addCleanup(os.close, fd2)
self.assertEqual(os.get_inheritable(fd2), False)
@unittest.skipUnless(hasattr(os, 'dup2'), "need os.dup2()")
def test_dup2(self):
fd = os.open(__file__, os.O_RDONLY)
self.addCleanup(os.close, fd)
# inheritable by default
fd2 = os.open(__file__, os.O_RDONLY)
try:
os.dup2(fd, fd2)
self.assertEqual(os.get_inheritable(fd2), True)
finally:
os.close(fd2)
# force non-inheritable
fd3 = os.open(__file__, os.O_RDONLY)
try:
os.dup2(fd, fd3, inheritable=False)
self.assertEqual(os.get_inheritable(fd3), False)
finally:
os.close(fd3)
@unittest.skipUnless(hasattr(os, 'openpty'), "need os.openpty()")
def test_openpty(self):
master_fd, slave_fd = os.openpty()
self.addCleanup(os.close, master_fd)
self.addCleanup(os.close, slave_fd)
self.assertEqual(os.get_inheritable(master_fd), False)
self.assertEqual(os.get_inheritable(slave_fd), False)
@support.reap_threads @support.reap_threads
def test_main(): def test_main():
support.run_unittest( support.run_unittest(
@ -2330,6 +2396,7 @@ def test_main():
OSErrorTests, OSErrorTests,
RemoveDirsTests, RemoveDirsTests,
CPUCountTests, CPUCountTests,
FDInheritanceTests,
) )
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -22,10 +22,6 @@ import signal
import math import math
import pickle import pickle
import struct import struct
try:
import fcntl
except ImportError:
fcntl = False
try: try:
import multiprocessing import multiprocessing
except ImportError: except ImportError:
@ -1108,9 +1104,15 @@ class GeneralModuleTests(unittest.TestCase):
def testNewAttributes(self): def testNewAttributes(self):
# testing .family, .type and .protocol # testing .family, .type and .protocol
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.assertEqual(sock.family, socket.AF_INET) self.assertEqual(sock.family, socket.AF_INET)
self.assertEqual(sock.type, socket.SOCK_STREAM) if hasattr(socket, 'SOCK_CLOEXEC'):
self.assertIn(sock.type,
(socket.SOCK_STREAM | socket.SOCK_CLOEXEC,
socket.SOCK_STREAM))
else:
self.assertEqual(sock.type, socket.SOCK_STREAM)
self.assertEqual(sock.proto, 0) self.assertEqual(sock.proto, 0)
sock.close() sock.close()
@ -4749,16 +4751,46 @@ class ContextManagersTest(ThreadedTCPSocketTest):
self.assertRaises(OSError, sock.sendall, b'foo') self.assertRaises(OSError, sock.sendall, b'foo')
@unittest.skipUnless(hasattr(socket, "SOCK_CLOEXEC"), class InheritanceTest(unittest.TestCase):
"SOCK_CLOEXEC not defined") @unittest.skipUnless(hasattr(socket, "SOCK_CLOEXEC"),
@unittest.skipUnless(fcntl, "module fcntl not available") "SOCK_CLOEXEC not defined")
class CloexecConstantTest(unittest.TestCase):
@support.requires_linux_version(2, 6, 28) @support.requires_linux_version(2, 6, 28)
def test_SOCK_CLOEXEC(self): def test_SOCK_CLOEXEC(self):
with socket.socket(socket.AF_INET, with socket.socket(socket.AF_INET,
socket.SOCK_STREAM | socket.SOCK_CLOEXEC) as s: socket.SOCK_STREAM | socket.SOCK_CLOEXEC) as s:
self.assertTrue(s.type & socket.SOCK_CLOEXEC) self.assertTrue(s.type & socket.SOCK_CLOEXEC)
self.assertTrue(fcntl.fcntl(s, fcntl.F_GETFD) & fcntl.FD_CLOEXEC) self.assertTrue(sock.get_inheritable())
def test_default_inheritable(self):
sock = socket.socket()
with sock:
self.assertEqual(sock.get_inheritable(), False)
def test_dup(self):
sock = socket.socket()
with sock:
newsock = sock.dup()
sock.close()
with newsock:
self.assertEqual(newsock.get_inheritable(), False)
def test_set_inheritable(self):
sock = socket.socket()
with sock:
sock.set_inheritable(True)
self.assertEqual(sock.get_inheritable(), True)
sock.set_inheritable(False)
self.assertEqual(sock.get_inheritable(), False)
@unittest.skipUnless(hasattr(socket, "socketpair"),
"need socket.socketpair()")
def test_socketpair(self):
s1, s2 = socket.socketpair()
self.addCleanup(s1.close)
self.addCleanup(s2.close)
self.assertEqual(s1.get_inheritable(), False)
self.assertEqual(s2.get_inheritable(), False)
@unittest.skipUnless(hasattr(socket, "SOCK_NONBLOCK"), @unittest.skipUnless(hasattr(socket, "SOCK_NONBLOCK"),
@ -4927,7 +4959,7 @@ def test_main():
NetworkConnectionAttributesTest, NetworkConnectionAttributesTest,
NetworkConnectionBehaviourTest, NetworkConnectionBehaviourTest,
ContextManagersTest, ContextManagersTest,
CloexecConstantTest, InheritanceTest,
NonblockConstantTest NonblockConstantTest
]) ])
if hasattr(socket, "socketpair"): if hasattr(socket, "socketpair"):

View file

@ -1501,16 +1501,28 @@ class POSIXProcessTestCase(BaseTestCase):
# Terminating a dead process # Terminating a dead process
self._kill_dead_process('terminate') self._kill_dead_process('terminate')
def _save_fds(self, save_fds):
fds = []
for fd in save_fds:
inheritable = os.get_inheritable(fd)
saved = os.dup(fd)
fds.append((fd, saved, inheritable))
return fds
def _restore_fds(self, fds):
for fd, saved, inheritable in fds:
os.dup2(saved, fd, inheritable=inheritable)
os.close(saved)
def check_close_std_fds(self, fds): def check_close_std_fds(self, fds):
# Issue #9905: test that subprocess pipes still work properly with # Issue #9905: test that subprocess pipes still work properly with
# some standard fds closed # some standard fds closed
stdin = 0 stdin = 0
newfds = [] saved_fds = self._save_fds(fds)
for a in fds: for fd, saved, inheritable in saved_fds:
b = os.dup(a) if fd == 0:
newfds.append(b) stdin = saved
if a == 0: break
stdin = b
try: try:
for fd in fds: for fd in fds:
os.close(fd) os.close(fd)
@ -1525,10 +1537,7 @@ class POSIXProcessTestCase(BaseTestCase):
err = support.strip_python_stderr(err) err = support.strip_python_stderr(err)
self.assertEqual((out, err), (b'apple', b'orange')) self.assertEqual((out, err), (b'apple', b'orange'))
finally: finally:
for b, a in zip(newfds, fds): self._restore_fds(saved_fds)
os.dup2(b, a)
for b in newfds:
os.close(b)
def test_close_fd_0(self): def test_close_fd_0(self):
self.check_close_std_fds([0]) self.check_close_std_fds([0])
@ -1568,7 +1577,7 @@ class POSIXProcessTestCase(BaseTestCase):
os.lseek(temp_fds[1], 0, 0) os.lseek(temp_fds[1], 0, 0)
# move the standard file descriptors out of the way # move the standard file descriptors out of the way
saved_fds = [os.dup(fd) for fd in range(3)] saved_fds = self._save_fds(range(3))
try: try:
# duplicate the file objects over the standard fd's # duplicate the file objects over the standard fd's
for fd, temp_fd in enumerate(temp_fds): for fd, temp_fd in enumerate(temp_fds):
@ -1584,10 +1593,7 @@ class POSIXProcessTestCase(BaseTestCase):
stderr=temp_fds[0]) stderr=temp_fds[0])
p.wait() p.wait()
finally: finally:
# restore the original fd's underneath sys.stdin, etc. self._restore_fds(saved_fds)
for std, saved in enumerate(saved_fds):
os.dup2(saved, std)
os.close(saved)
for fd in temp_fds: for fd in temp_fds:
os.lseek(fd, 0, 0) os.lseek(fd, 0, 0)
@ -1611,7 +1617,7 @@ class POSIXProcessTestCase(BaseTestCase):
os.unlink(fname) os.unlink(fname)
# save a copy of the standard file descriptors # save a copy of the standard file descriptors
saved_fds = [os.dup(fd) for fd in range(3)] saved_fds = self._save_fds(range(3))
try: try:
# duplicate the temp files over the standard fd's 0, 1, 2 # duplicate the temp files over the standard fd's 0, 1, 2
for fd, temp_fd in enumerate(temp_fds): for fd, temp_fd in enumerate(temp_fds):
@ -1637,9 +1643,7 @@ class POSIXProcessTestCase(BaseTestCase):
out = os.read(stdout_no, 1024) out = os.read(stdout_no, 1024)
err = support.strip_python_stderr(os.read(stderr_no, 1024)) err = support.strip_python_stderr(os.read(stderr_no, 1024))
finally: finally:
for std, saved in enumerate(saved_fds): self._restore_fds(saved_fds)
os.dup2(saved, std)
os.close(saved)
self.assertEqual(out, b"got STDIN") self.assertEqual(out, b"got STDIN")
self.assertEqual(err, b"err") self.assertEqual(err, b"err")
@ -1810,6 +1814,9 @@ class POSIXProcessTestCase(BaseTestCase):
self.addCleanup(os.close, fd) self.addCleanup(os.close, fd)
open_fds.add(fd) open_fds.add(fd)
for fd in open_fds:
os.set_inheritable(fd, True)
p = subprocess.Popen([sys.executable, fd_status], p = subprocess.Popen([sys.executable, fd_status],
stdout=subprocess.PIPE, close_fds=False) stdout=subprocess.PIPE, close_fds=False)
output, ignored = p.communicate() output, ignored = p.communicate()
@ -1854,6 +1861,8 @@ class POSIXProcessTestCase(BaseTestCase):
fds = os.pipe() fds = os.pipe()
self.addCleanup(os.close, fds[0]) self.addCleanup(os.close, fds[0])
self.addCleanup(os.close, fds[1]) self.addCleanup(os.close, fds[1])
os.set_inheritable(fds[0], True)
os.set_inheritable(fds[1], True)
open_fds.update(fds) open_fds.update(fds)
for fd in open_fds: for fd in open_fds:
@ -1876,6 +1885,32 @@ class POSIXProcessTestCase(BaseTestCase):
close_fds=False, pass_fds=(fd, ))) close_fds=False, pass_fds=(fd, )))
self.assertIn('overriding close_fds', str(context.warning)) self.assertIn('overriding close_fds', str(context.warning))
def test_pass_fds_inheritable(self):
script = support.findfile("inherited.py", subdir="subprocessdata")
inheritable, non_inheritable = os.pipe()
self.addCleanup(os.close, inheritable)
self.addCleanup(os.close, non_inheritable)
os.set_inheritable(inheritable, True)
os.set_inheritable(non_inheritable, False)
pass_fds = (inheritable, non_inheritable)
args = [sys.executable, script]
args += list(map(str, pass_fds))
p = subprocess.Popen(args,
stdout=subprocess.PIPE, close_fds=True,
pass_fds=pass_fds)
output, ignored = p.communicate()
fds = set(map(int, output.split(b',')))
# the inheritable file descriptor must be inherited, so its inheritable
# flag must be set in the child process after fork() and before exec()
self.assertEqual(fds, set(pass_fds))
# inheritable flag must not be changed in the parent process
self.assertEqual(os.get_inheritable(inheritable), True)
self.assertEqual(os.get_inheritable(non_inheritable), False)
def test_stdout_stdin_are_single_inout_fd(self): def test_stdout_stdin_are_single_inout_fd(self):
with io.open(os.devnull, "r+") as inout: with io.open(os.devnull, "r+") as inout:
p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"], p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"],

View file

@ -333,6 +333,7 @@ class TestMkstempInner(BaseTestCase):
v="q" v="q"
file = self.do_create() file = self.do_create()
self.assertEqual(os.get_inheritable(file.fd), False)
fd = "%d" % file.fd fd = "%d" % file.fd
try: try:

View file

@ -584,13 +584,6 @@ class SimpleXMLRPCServer(socketserver.TCPServer,
SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding, use_builtin_types) SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding, use_builtin_types)
socketserver.TCPServer.__init__(self, addr, requestHandler, bind_and_activate) socketserver.TCPServer.__init__(self, addr, requestHandler, bind_and_activate)
# [Bug #1222790] If possible, set close-on-exec flag; if a
# method spawns a subprocess, the subprocess shouldn't have
# the listening socket open.
if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
class MultiPathXMLRPCServer(SimpleXMLRPCServer): class MultiPathXMLRPCServer(SimpleXMLRPCServer):
"""Multipath XML-RPC Server """Multipath XML-RPC Server

View file

@ -10,6 +10,11 @@ Projected Release date: 2013-09-08
Core and Builtins 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 - Issue #11619: The parser and the import machinery do not encode Unicode
filenames anymore on Windows. filenames anymore on Windows.

View file

@ -1694,26 +1694,24 @@ PyCursesWindow_PutWin(PyCursesWindowObject *self, PyObject *stream)
/* We have to simulate this by writing to a temporary FILE*, /* We have to simulate this by writing to a temporary FILE*,
then reading back, then writing to the argument stream. */ then reading back, then writing to the argument stream. */
char fn[100]; char fn[100];
int fd; int fd = -1;
FILE *fp; FILE *fp = NULL;
PyObject *res; PyObject *res = NULL;
strcpy(fn, "/tmp/py.curses.putwin.XXXXXX"); strcpy(fn, "/tmp/py.curses.putwin.XXXXXX");
fd = mkstemp(fn); fd = mkstemp(fn);
if (fd < 0) if (fd < 0)
return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn); return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
if (_Py_set_inheritable(fd, 0, NULL) < 0)
goto exit;
fp = fdopen(fd, "wb+"); fp = fdopen(fd, "wb+");
if (fp == NULL) { if (fp == NULL) {
close(fd); PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
remove(fn); goto exit;
return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
} }
res = PyCursesCheckERR(putwin(self->win, fp), "putwin"); res = PyCursesCheckERR(putwin(self->win, fp), "putwin");
if (res == NULL) { if (res == NULL)
fclose(fp); goto exit;
remove(fn);
return res;
}
fseek(fp, 0, 0); fseek(fp, 0, 0);
while (1) { while (1) {
char buf[BUFSIZ]; char buf[BUFSIZ];
@ -1727,7 +1725,12 @@ PyCursesWindow_PutWin(PyCursesWindowObject *self, PyObject *stream)
if (res == NULL) if (res == NULL)
break; break;
} }
fclose(fp);
exit:
if (fp != NULL)
fclose(fp);
else if (fd != -1)
close(fd);
remove(fn); remove(fn);
return res; return res;
} }
@ -2252,12 +2255,13 @@ static PyObject *
PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream) PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream)
{ {
char fn[100]; char fn[100];
int fd; int fd = -1;
FILE *fp; FILE *fp = NULL;
PyObject *data; PyObject *data;
size_t datalen; size_t datalen;
WINDOW *win; WINDOW *win;
_Py_IDENTIFIER(read); _Py_IDENTIFIER(read);
PyObject *res = NULL;
PyCursesInitialised; PyCursesInitialised;
@ -2265,44 +2269,47 @@ PyCurses_GetWin(PyCursesWindowObject *self, PyObject *stream)
fd = mkstemp(fn); fd = mkstemp(fn);
if (fd < 0) if (fd < 0)
return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn); return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
if (_Py_set_inheritable(fd, 0, NULL) < 0)
goto error;
fp = fdopen(fd, "wb+"); fp = fdopen(fd, "wb+");
if (fp == NULL) { if (fp == NULL) {
close(fd); PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
remove(fn); goto error;
return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
} }
data = _PyObject_CallMethodId(stream, &PyId_read, ""); data = _PyObject_CallMethodId(stream, &PyId_read, "");
if (data == NULL) { if (data == NULL)
fclose(fp); goto error;
remove(fn);
return NULL;
}
if (!PyBytes_Check(data)) { if (!PyBytes_Check(data)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"f.read() returned %.100s instead of bytes", "f.read() returned %.100s instead of bytes",
data->ob_type->tp_name); data->ob_type->tp_name);
Py_DECREF(data); Py_DECREF(data);
fclose(fp); goto error;
remove(fn);
return NULL;
} }
datalen = PyBytes_GET_SIZE(data); datalen = PyBytes_GET_SIZE(data);
if (fwrite(PyBytes_AS_STRING(data), 1, datalen, fp) != datalen) { if (fwrite(PyBytes_AS_STRING(data), 1, datalen, fp) != datalen) {
Py_DECREF(data); Py_DECREF(data);
fclose(fp); PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
remove(fn); goto error;
return PyErr_SetFromErrnoWithFilename(PyExc_IOError, fn);
} }
Py_DECREF(data); Py_DECREF(data);
fseek(fp, 0, 0); fseek(fp, 0, 0);
win = getwin(fp); win = getwin(fp);
fclose(fp);
remove(fn);
if (win == NULL) { if (win == NULL) {
PyErr_SetString(PyCursesError, catchall_NULL); PyErr_SetString(PyCursesError, catchall_NULL);
return NULL; goto error;
} }
return PyCursesWindow_New(win, NULL); res = PyCursesWindow_New(win, NULL);
error:
if (fp != NULL)
fclose(fp);
else if (fd != -1)
close(fd);
remove(fn);
return res;
} }
static PyObject * static PyObject *

View file

@ -202,6 +202,9 @@ check_fd(int fd)
return 0; return 0;
} }
#ifdef O_CLOEXEC
extern int _Py_open_cloexec_works;
#endif
static int static int
fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
@ -221,6 +224,11 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
int fd = -1; int fd = -1;
int closefd = 1; int closefd = 1;
int fd_is_own = 0; int fd_is_own = 0;
#ifdef O_CLOEXEC
int *atomic_flag_works = &_Py_open_cloexec_works;
#elif !defined(MS_WINDOWS)
int *atomic_flag_works = NULL;
#endif
assert(PyFileIO_Check(oself)); assert(PyFileIO_Check(oself));
if (self->fd >= 0) { if (self->fd >= 0) {
@ -345,6 +353,11 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
if (append) if (append)
flags |= O_APPEND; flags |= O_APPEND;
#endif #endif
#ifdef MS_WINDOWS
flags |= O_NOINHERIT;
#elif defined(O_CLOEXEC)
flags |= O_CLOEXEC;
#endif
if (fd >= 0) { if (fd >= 0) {
if (check_fd(fd)) if (check_fd(fd))
@ -369,10 +382,18 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
else else
#endif #endif
self->fd = open(name, flags, 0666); self->fd = open(name, flags, 0666);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
} else { }
PyObject *fdobj = PyObject_CallFunction( else {
opener, "Oi", nameobj, flags); PyObject *fdobj;
#ifndef MS_WINDOWS
/* the opener may clear the atomic flag */
atomic_flag_works = NULL;
#endif
fdobj = PyObject_CallFunction(opener, "Oi", nameobj, flags);
if (fdobj == NULL) if (fdobj == NULL)
goto error; goto error;
if (!PyLong_Check(fdobj)) { if (!PyLong_Check(fdobj)) {
@ -394,6 +415,11 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
goto error; goto error;
} }
#ifndef MS_WINDOWS
if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0)
goto error;
#endif
} }
if (dircheck(self, nameobj) < 0) if (dircheck(self, nameobj) < 0)
goto error; goto error;

View file

@ -35,7 +35,7 @@
# define FD_DIR "/proc/self/fd" # define FD_DIR "/proc/self/fd"
#endif #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. */ /* Maximum file descriptor, initialized on module load. */
@ -87,7 +87,7 @@ _is_fdescfs_mounted_on_dev_fd(void)
if (stat("/dev", &dev_stat) != 0) if (stat("/dev", &dev_stat) != 0)
return 0; return 0;
if (stat(FD_DIR, &dev_fd_stat) != 0) if (stat(FD_DIR, &dev_fd_stat) != 0)
return 0; return 0;
if (dev_stat.st_dev == dev_fd_stat.st_dev) if (dev_stat.st_dev == dev_fd_stat.st_dev)
return 0; /* / == /dev == /dev/fd means it is static. #fail */ return 0; /* / == /dev == /dev/fd means it is static. #fail */
return 1; return 1;
@ -136,6 +136,29 @@ _is_fd_in_sorted_fd_sequence(int fd, PyObject *fd_sequence)
return 0; return 0;
} }
static int
make_inheritable(PyObject *py_fds_to_keep, int errpipe_write)
{
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);
long fd = PyLong_AsLong(fdobj);
assert(!PyErr_Occurred());
assert(0 <= fd && fd <= INT_MAX);
if (fd == errpipe_write) {
/* errpipe_write is part of py_fds_to_keep. It must be closed at
exec(), but kept open in the child process until exec() is
called. */
continue;
}
if (_Py_set_inheritable((int)fd, 1, NULL) < 0)
return -1;
}
return 0;
}
/* Close all file descriptors in the range start_fd inclusive to /* Close all file descriptors in the range start_fd inclusive to
* end_fd exclusive except for those in py_fds_to_keep. If the * end_fd exclusive except for those in py_fds_to_keep. If the
@ -205,18 +228,8 @@ _close_open_fd_range_safe(int start_fd, int end_fd, PyObject* py_fds_to_keep)
int fd_dir_fd; int fd_dir_fd;
if (start_fd >= end_fd) if (start_fd >= end_fd)
return; return;
#ifdef O_CLOEXEC
fd_dir_fd = open(FD_DIR, O_RDONLY | O_CLOEXEC, 0); fd_dir_fd = _Py_open(FD_DIR, O_RDONLY);
#else
fd_dir_fd = open(FD_DIR, O_RDONLY, 0);
#ifdef FD_CLOEXEC
{
int old = fcntl(fd_dir_fd, F_GETFD);
if (old != -1)
fcntl(fd_dir_fd, F_SETFD, old | FD_CLOEXEC);
}
#endif
#endif
if (fd_dir_fd == -1) { if (fd_dir_fd == -1) {
/* No way to get a list of open fds. */ /* No way to get a list of open fds. */
_close_fds_by_brute_force(start_fd, end_fd, py_fds_to_keep); _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. */ /* Buffer large enough to hold a hex integer. We can't malloc. */
char hex_errno[sizeof(saved_errno)*2+1]; char hex_errno[sizeof(saved_errno)*2+1];
if (make_inheritable(py_fds_to_keep, errpipe_write) < 0)
goto error;
/* Close parent's pipe ends. */ /* Close parent's pipe ends. */
if (p2cwrite != -1) { if (p2cwrite != -1)
POSIX_CALL(close(p2cwrite)); POSIX_CALL(close(p2cwrite));
} if (c2pread != -1)
if (c2pread != -1) {
POSIX_CALL(close(c2pread)); POSIX_CALL(close(c2pread));
} if (errread != -1)
if (errread != -1) {
POSIX_CALL(close(errread)); POSIX_CALL(close(errread));
}
POSIX_CALL(close(errpipe_read)); POSIX_CALL(close(errpipe_read));
/* When duping fds, if there arises a situation where one of the fds is /* 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() dup2() removes the CLOEXEC flag but we must do it ourselves if dup2()
would be a no-op (issue #10806). */ would be a no-op (issue #10806). */
if (p2cread == 0) { if (p2cread == 0) {
int old = fcntl(p2cread, F_GETFD); if (_Py_set_inheritable(p2cread, 1, NULL) < 0)
if (old != -1) goto error;
fcntl(p2cread, F_SETFD, old & ~FD_CLOEXEC); }
} else if (p2cread != -1) { else if (p2cread != -1)
POSIX_CALL(dup2(p2cread, 0)); /* stdin */ POSIX_CALL(dup2(p2cread, 0)); /* stdin */
}
if (c2pwrite == 1) { if (c2pwrite == 1) {
int old = fcntl(c2pwrite, F_GETFD); if (_Py_set_inheritable(c2pwrite, 1, NULL) < 0)
if (old != -1) goto error;
fcntl(c2pwrite, F_SETFD, old & ~FD_CLOEXEC); }
} else if (c2pwrite != -1) { else if (c2pwrite != -1)
POSIX_CALL(dup2(c2pwrite, 1)); /* stdout */ POSIX_CALL(dup2(c2pwrite, 1)); /* stdout */
}
if (errwrite == 2) { if (errwrite == 2) {
int old = fcntl(errwrite, F_GETFD); if (_Py_set_inheritable(errwrite, 1, NULL) < 0)
if (old != -1) goto error;
fcntl(errwrite, F_SETFD, old & ~FD_CLOEXEC);
} else if (errwrite != -1) {
POSIX_CALL(dup2(errwrite, 2)); /* stderr */
} }
else if (errwrite != -1)
POSIX_CALL(dup2(errwrite, 2)); /* stderr */
/* Close pipe fds. Make sure we don't close the same fd more than */ /* Close pipe fds. Make sure we don't close the same fd more than */
/* once, or standard fds. */ /* once, or standard fds. */
if (p2cread > 2) { if (p2cread > 2)
POSIX_CALL(close(p2cread)); POSIX_CALL(close(p2cread));
} if (c2pwrite > 2 && c2pwrite != p2cread)
if (c2pwrite > 2 && c2pwrite != p2cread) {
POSIX_CALL(close(c2pwrite)); POSIX_CALL(close(c2pwrite));
} if (errwrite != c2pwrite && errwrite != p2cread && errwrite > 2)
if (errwrite != c2pwrite && errwrite != p2cread && errwrite > 2) {
POSIX_CALL(close(errwrite)); POSIX_CALL(close(errwrite));
}
if (cwd) if (cwd)
POSIX_CALL(chdir(cwd)); POSIX_CALL(chdir(cwd));
@ -544,7 +553,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
PyObject *result; PyObject *result;
_Py_IDENTIFIER(isenabled); _Py_IDENTIFIER(isenabled);
_Py_IDENTIFIER(disable); _Py_IDENTIFIER(disable);
gc_module = PyImport_ImportModule("gc"); gc_module = PyImport_ImportModule("gc");
if (gc_module == NULL) if (gc_module == NULL)
return NULL; return NULL;
@ -721,52 +730,6 @@ Returns: the child process's PID.\n\
Raises: Only on an error in the parent process.\n\ Raises: Only on an error in the parent process.\n\
"); ");
PyDoc_STRVAR(subprocess_cloexec_pipe_doc,
"cloexec_pipe() -> (read_end, write_end)\n\n\
Create a pipe whose ends have the cloexec flag set.");
static PyObject *
subprocess_cloexec_pipe(PyObject *self, PyObject *noargs)
{
int fds[2];
int res;
#ifdef HAVE_PIPE2
Py_BEGIN_ALLOW_THREADS
res = pipe2(fds, O_CLOEXEC);
Py_END_ALLOW_THREADS
if (res != 0 && errno == ENOSYS)
{
{
#endif
/* We hold the GIL which offers some protection from other code calling
* fork() before the CLOEXEC flags have been set but we can't guarantee
* anything without pipe2(). */
long oldflags;
res = pipe(fds);
if (res == 0) {
oldflags = fcntl(fds[0], F_GETFD, 0);
if (oldflags < 0) res = oldflags;
}
if (res == 0)
res = fcntl(fds[0], F_SETFD, oldflags | FD_CLOEXEC);
if (res == 0) {
oldflags = fcntl(fds[1], F_GETFD, 0);
if (oldflags < 0) res = oldflags;
}
if (res == 0)
res = fcntl(fds[1], F_SETFD, oldflags | FD_CLOEXEC);
#ifdef HAVE_PIPE2
}
}
#endif
if (res != 0)
return PyErr_SetFromErrno(PyExc_OSError);
return Py_BuildValue("(ii)", fds[0], fds[1]);
}
/* module level code ********************************************************/ /* module level code ********************************************************/
PyDoc_STRVAR(module_doc, PyDoc_STRVAR(module_doc,
@ -775,7 +738,6 @@ PyDoc_STRVAR(module_doc,
static PyMethodDef module_methods[] = { static PyMethodDef module_methods[] = {
{"fork_exec", subprocess_fork_exec, METH_VARARGS, subprocess_fork_exec_doc}, {"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 */ {NULL, NULL} /* sentinel */
}; };

View file

@ -2350,7 +2350,7 @@ load_dh_params(PySSLContext *self, PyObject *filepath)
FILE *f; FILE *f;
DH *dh; DH *dh;
f = _Py_fopen(filepath, "rb"); f = _Py_fopen_obj(filepath, "rb");
if (f == NULL) { if (f == NULL) {
if (!PyErr_Occurred()) if (!PyErr_Occurred())
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath); PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath);

View file

@ -143,7 +143,7 @@ static void RunStartupFile(PyCompilerFlags *cf)
{ {
char *startup = Py_GETENV("PYTHONSTARTUP"); char *startup = Py_GETENV("PYTHONSTARTUP");
if (startup != NULL && startup[0] != '\0') { if (startup != NULL && startup[0] != '\0') {
FILE *fp = fopen(startup, "r"); FILE *fp = _Py_fopen(startup, "r");
if (fp != NULL) { if (fp != NULL) {
(void) PyRun_SimpleFileExFlags(fp, startup, 0, cf); (void) PyRun_SimpleFileExFlags(fp, startup, 0, cf);
PyErr_Clear(); PyErr_Clear();

View file

@ -1208,18 +1208,18 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
flags |= MAP_ANONYMOUS; flags |= MAP_ANONYMOUS;
#else #else
/* SVR4 method to map anonymous memory is to open /dev/zero */ /* SVR4 method to map anonymous memory is to open /dev/zero */
fd = devzero = open("/dev/zero", O_RDWR); fd = devzero = _Py_open("/dev/zero", O_RDWR);
if (devzero == -1) { if (devzero == -1) {
Py_DECREF(m_obj); Py_DECREF(m_obj);
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
#endif #endif
} else { }
m_obj->fd = dup(fd); else {
m_obj->fd = _Py_dup(fd);
if (m_obj->fd == -1) { if (m_obj->fd == -1) {
Py_DECREF(m_obj); Py_DECREF(m_obj);
PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
} }

View file

@ -115,7 +115,9 @@ newossobject(PyObject *arg)
one open at a time. This does *not* affect later I/O; OSS one open at a time. This does *not* affect later I/O; OSS
provides a special ioctl() for non-blocking read/write, which is provides a special ioctl() for non-blocking read/write, which is
exposed via oss_nonblock() below. */ exposed via oss_nonblock() below. */
if ((fd = open(devicename, imode|O_NONBLOCK)) == -1) { fd = _Py_open(devicename, imode|O_NONBLOCK);
if (fd == -1) {
PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename); PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL; return NULL;
} }
@ -177,7 +179,8 @@ newossmixerobject(PyObject *arg)
devicename = "/dev/mixer"; devicename = "/dev/mixer";
} }
if ((fd = open(devicename, O_RDWR)) == -1) { fd = _Py_open(devicename, O_RDWR);
if (fd == -1) {
PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename); PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename);
return NULL; return NULL;
} }

View file

@ -3535,10 +3535,7 @@ _posix_listdir(path_t *path, PyObject *list)
#ifdef HAVE_FDOPENDIR #ifdef HAVE_FDOPENDIR
if (path->fd != -1) { if (path->fd != -1) {
/* closedir() closes the FD, so we duplicate it */ /* closedir() closes the FD, so we duplicate it */
Py_BEGIN_ALLOW_THREADS fd = _Py_dup(path->fd);
fd = dup(path->fd);
Py_END_ALLOW_THREADS
if (fd == -1) { if (fd == -1) {
list = posix_error(); list = posix_error();
goto exit; goto exit;
@ -5768,7 +5765,7 @@ Open a pseudo-terminal, returning open fd's for both master and slave end.\n");
static PyObject * static PyObject *
posix_openpty(PyObject *self, PyObject *noargs) posix_openpty(PyObject *self, PyObject *noargs)
{ {
int master_fd, slave_fd; int master_fd = -1, slave_fd = -1;
#ifndef HAVE_OPENPTY #ifndef HAVE_OPENPTY
char * slave_name; char * slave_name;
#endif #endif
@ -5781,37 +5778,52 @@ posix_openpty(PyObject *self, PyObject *noargs)
#ifdef HAVE_OPENPTY #ifdef HAVE_OPENPTY
if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0) if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0)
return posix_error(); goto posix_error;
if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
goto error;
if (_Py_set_inheritable(slave_fd, 0, NULL) < 0)
goto error;
#elif defined(HAVE__GETPTY) #elif defined(HAVE__GETPTY)
slave_name = _getpty(&master_fd, O_RDWR, 0666, 0); slave_name = _getpty(&master_fd, O_RDWR, 0666, 0);
if (slave_name == NULL) if (slave_name == NULL)
return posix_error(); goto posix_error;
if (_Py_set_inheritable(master_fd, 0, NULL) < 0)
goto error;
slave_fd = open(slave_name, O_RDWR); slave_fd = _Py_open(slave_name, O_RDWR);
if (slave_fd < 0) if (slave_fd < 0)
return posix_error(); goto posix_error;
#else #else
master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */ master_fd = _Py_open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */
if (master_fd < 0) if (master_fd < 0)
return posix_error(); goto posix_error;
sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL); sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL);
/* change permission of slave */ /* change permission of slave */
if (grantpt(master_fd) < 0) { if (grantpt(master_fd) < 0) {
PyOS_setsig(SIGCHLD, sig_saved); PyOS_setsig(SIGCHLD, sig_saved);
return posix_error(); goto posix_error;
} }
/* unlock slave */ /* unlock slave */
if (unlockpt(master_fd) < 0) { if (unlockpt(master_fd) < 0) {
PyOS_setsig(SIGCHLD, sig_saved); PyOS_setsig(SIGCHLD, sig_saved);
return posix_error(); goto posix_error;
} }
PyOS_setsig(SIGCHLD, sig_saved); PyOS_setsig(SIGCHLD, sig_saved);
slave_name = ptsname(master_fd); /* get name of slave */ slave_name = ptsname(master_fd); /* get name of slave */
if (slave_name == NULL) if (slave_name == NULL)
return posix_error(); goto posix_error;
slave_fd = open(slave_name, O_RDWR | O_NOCTTY); /* open slave */
slave_fd = _Py_open(slave_name, O_RDWR | O_NOCTTY); /* open slave */
if (slave_fd < 0) if (slave_fd < 0)
return posix_error(); goto posix_error;
#if !defined(__CYGWIN__) && !defined(HAVE_DEV_PTC) #if !defined(__CYGWIN__) && !defined(HAVE_DEV_PTC)
ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */ ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */
ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */ ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */
@ -5823,6 +5835,14 @@ posix_openpty(PyObject *self, PyObject *noargs)
return Py_BuildValue("(ii)", master_fd, slave_fd); return Py_BuildValue("(ii)", master_fd, slave_fd);
posix_error:
posix_error();
error:
if (master_fd != -1)
close(master_fd);
if (slave_fd != -1)
close(slave_fd);
return NULL;
} }
#endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */ #endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */
@ -7432,6 +7452,10 @@ posix_tcsetpgrp(PyObject *self, PyObject *args)
/* Functions acting on file descriptors */ /* Functions acting on file descriptors */
#ifdef O_CLOEXEC
extern int _Py_open_cloexec_works;
#endif
PyDoc_STRVAR(posix_open__doc__, PyDoc_STRVAR(posix_open__doc__,
"open(path, flags, mode=0o777, *, dir_fd=None)\n\n\ "open(path, flags, mode=0o777, *, dir_fd=None)\n\n\
Open a file for low level IO. Returns a file handle (integer).\n\ Open a file for low level IO. Returns a file handle (integer).\n\
@ -7451,6 +7475,11 @@ posix_open(PyObject *self, PyObject *args, PyObject *kwargs)
int fd; int fd;
PyObject *return_value = NULL; PyObject *return_value = NULL;
static char *keywords[] = {"path", "flags", "mode", "dir_fd", NULL}; static char *keywords[] = {"path", "flags", "mode", "dir_fd", NULL};
#ifdef O_CLOEXEC
int *atomic_flag_works = &_Py_open_cloexec_works;
#elif !defined(MS_WINDOWS)
int *atomic_flag_works = NULL;
#endif
memset(&path, 0, sizeof(path)); memset(&path, 0, sizeof(path));
path.function_name = "open"; path.function_name = "open";
@ -7465,6 +7494,12 @@ posix_open(PyObject *self, PyObject *args, PyObject *kwargs)
)) ))
return NULL; return NULL;
#ifdef MS_WINDOWS
flags |= O_NOINHERIT;
#elif defined(O_CLOEXEC)
flags |= O_CLOEXEC;
#endif
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
if (path.wide) if (path.wide)
@ -7484,6 +7519,13 @@ posix_open(PyObject *self, PyObject *args, PyObject *kwargs)
goto exit; goto exit;
} }
#ifndef MS_WINDOWS
if (_Py_set_inheritable(fd, 0, atomic_flag_works) < 0) {
close(fd);
goto exit;
}
#endif
return_value = PyLong_FromLong((long)fd); return_value = PyLong_FromLong((long)fd);
exit: exit:
@ -7540,13 +7582,14 @@ static PyObject *
posix_dup(PyObject *self, PyObject *args) posix_dup(PyObject *self, PyObject *args)
{ {
int fd; int fd;
if (!PyArg_ParseTuple(args, "i:dup", &fd)) if (!PyArg_ParseTuple(args, "i:dup", &fd))
return NULL; return NULL;
if (!_PyVerify_fd(fd))
return posix_error(); fd = _Py_dup(fd);
fd = dup(fd); if (fd == -1)
if (fd < 0) return NULL;
return posix_error();
return PyLong_FromLong((long)fd); return PyLong_FromLong((long)fd);
} }
@ -7556,16 +7599,82 @@ PyDoc_STRVAR(posix_dup2__doc__,
Duplicate file descriptor."); Duplicate file descriptor.");
static PyObject * static PyObject *
posix_dup2(PyObject *self, PyObject *args) posix_dup2(PyObject *self, PyObject *args, PyObject *kwargs)
{ {
int fd, fd2, res; static char *keywords[] = {"fd", "fd2", "inheritable", NULL};
if (!PyArg_ParseTuple(args, "ii:dup2", &fd, &fd2)) int fd, fd2;
int inheritable = 1;
int res;
#if defined(HAVE_DUP3) && \
!(defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC))
/* dup3() is available on Linux 2.6.27+ and glibc 2.9 */
int dup3_works = -1;
#endif
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|i:dup2", keywords,
&fd, &fd2, &inheritable))
return NULL; return NULL;
if (!_PyVerify_fd_dup2(fd, fd2)) if (!_PyVerify_fd_dup2(fd, fd2))
return posix_error(); return posix_error();
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
res = dup2(fd, fd2); res = dup2(fd, fd2);
Py_END_ALLOW_THREADS
if (res < 0) if (res < 0)
return posix_error(); return posix_error();
/* Character files like console cannot be make non-inheritable */
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
close(fd2);
return NULL;
}
#elif defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)
Py_BEGIN_ALLOW_THREADS
if (!inheritable)
res = fcntl(fd, F_DUP2FD_CLOEXEC, fd2);
else
res = dup2(fd, fd2);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error();
#else
#ifdef HAVE_DUP3
if (!inheritable && dup3_works != 0) {
Py_BEGIN_ALLOW_THREADS
res = dup3(fd, fd2, O_CLOEXEC);
Py_END_ALLOW_THREADS
if (res < 0) {
if (dup3_works == -1)
dup3_works = (errno != ENOSYS);
if (dup3_works)
return posix_error();
}
}
if (inheritable || dup3_works == 0)
{
#endif
Py_BEGIN_ALLOW_THREADS
res = dup2(fd, fd2);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error();
if (!inheritable && _Py_set_inheritable(fd2, 0, NULL) < 0) {
close(fd2);
return NULL;
}
#ifdef HAVE_DUP3
}
#endif
#endif
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
@ -8052,24 +8161,69 @@ Create a pipe.");
static PyObject * static PyObject *
posix_pipe(PyObject *self, PyObject *noargs) posix_pipe(PyObject *self, PyObject *noargs)
{ {
#if !defined(MS_WINDOWS)
int fds[2]; int fds[2];
int res; #ifdef MS_WINDOWS
res = pipe(fds);
if (res != 0)
return posix_error();
return Py_BuildValue("(ii)", fds[0], fds[1]);
#else /* MS_WINDOWS */
HANDLE read, write; HANDLE read, write;
int read_fd, write_fd; SECURITY_ATTRIBUTES attr;
BOOL ok; BOOL ok;
ok = CreatePipe(&read, &write, NULL, 0); #else
int res;
#endif
#ifdef MS_WINDOWS
attr.nLength = sizeof(attr);
attr.lpSecurityDescriptor = NULL;
attr.bInheritHandle = FALSE;
Py_BEGIN_ALLOW_THREADS
ok = CreatePipe(&read, &write, &attr, 0);
if (ok) {
fds[0] = _open_osfhandle((Py_intptr_t)read, _O_RDONLY);
fds[1] = _open_osfhandle((Py_intptr_t)write, _O_WRONLY);
if (fds[0] == -1 || fds[1] == -1) {
CloseHandle(read);
CloseHandle(write);
ok = 0;
}
}
Py_END_ALLOW_THREADS
if (!ok) if (!ok)
return PyErr_SetFromWindowsErr(0); return PyErr_SetFromWindowsErr(0);
read_fd = _open_osfhandle((Py_intptr_t)read, 0); #else
write_fd = _open_osfhandle((Py_intptr_t)write, 1);
return Py_BuildValue("(ii)", read_fd, write_fd); #ifdef HAVE_PIPE2
#endif /* MS_WINDOWS */ Py_BEGIN_ALLOW_THREADS
res = pipe2(fds, O_CLOEXEC);
Py_END_ALLOW_THREADS
if (res != 0 && errno == ENOSYS)
{
#endif
Py_BEGIN_ALLOW_THREADS
res = pipe(fds);
Py_END_ALLOW_THREADS
if (res == 0) {
if (_Py_set_inheritable(fds[0], 0, NULL) < 0) {
close(fds[0]);
close(fds[1]);
return NULL;
}
if (_Py_set_inheritable(fds[1], 0, NULL) < 0) {
close(fds[0]);
close(fds[1]);
return NULL;
}
}
#ifdef HAVE_PIPE2
}
#endif
if (res != 0)
return PyErr_SetFromErrno(PyExc_OSError);
#endif /* !MS_WINDOWS */
return Py_BuildValue("(ii)", fds[0], fds[1]);
} }
#endif /* HAVE_PIPE */ #endif /* HAVE_PIPE */
@ -10659,6 +10813,102 @@ posix_cpu_count(PyObject *self)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
PyDoc_STRVAR(get_inheritable__doc__,
"get_inheritable(fd) -> bool\n" \
"\n" \
"Get the close-on-exe flag of the specified file descriptor.");
static PyObject*
posix_get_inheritable(PyObject *self, PyObject *args)
{
int fd;
int inheritable;
if (!PyArg_ParseTuple(args, "i:get_inheritable", &fd))
return NULL;
if (!_PyVerify_fd(fd))
return posix_error();
inheritable = _Py_get_inheritable(fd);
if (inheritable < 0)
return NULL;
return PyBool_FromLong(inheritable);
}
PyDoc_STRVAR(set_inheritable__doc__,
"set_inheritable(fd, inheritable)\n" \
"\n" \
"Set the inheritable flag of the specified file descriptor.");
static PyObject*
posix_set_inheritable(PyObject *self, PyObject *args)
{
int fd, inheritable;
if (!PyArg_ParseTuple(args, "ii:set_inheritable", &fd, &inheritable))
return NULL;
if (!_PyVerify_fd(fd))
return posix_error();
if (_Py_set_inheritable(fd, inheritable, NULL) < 0)
return NULL;
Py_RETURN_NONE;
}
#ifdef MS_WINDOWS
PyDoc_STRVAR(get_handle_inheritable__doc__,
"get_handle_inheritable(fd) -> bool\n" \
"\n" \
"Get the close-on-exe flag of the specified file descriptor.");
static PyObject*
posix_get_handle_inheritable(PyObject *self, PyObject *args)
{
Py_intptr_t handle;
DWORD flags;
if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR ":get_handle_inheritable", &handle))
return NULL;
if (!GetHandleInformation((HANDLE)handle, &flags)) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
return PyBool_FromLong(flags & HANDLE_FLAG_INHERIT);
}
PyDoc_STRVAR(set_handle_inheritable__doc__,
"set_handle_inheritable(fd, inheritable)\n" \
"\n" \
"Set the inheritable flag of the specified handle.");
static PyObject*
posix_set_handle_inheritable(PyObject *self, PyObject *args)
{
int inheritable = 1;
Py_intptr_t handle;
DWORD flags;
if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR "i:set_handle_inheritable",
&handle, &inheritable))
return NULL;
if (inheritable)
flags = HANDLE_FLAG_INHERIT;
else
flags = 0;
if (!SetHandleInformation((HANDLE)handle, HANDLE_FLAG_INHERIT, flags)) {
PyErr_SetFromWindowsErr(0);
return NULL;
}
Py_RETURN_NONE;
}
#endif /* MS_WINDOWS */
static PyMethodDef posix_methods[] = { static PyMethodDef posix_methods[] = {
{"access", (PyCFunction)posix_access, {"access", (PyCFunction)posix_access,
@ -10934,7 +11184,8 @@ static PyMethodDef posix_methods[] = {
{"closerange", posix_closerange, METH_VARARGS, posix_closerange__doc__}, {"closerange", posix_closerange, METH_VARARGS, posix_closerange__doc__},
{"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__}, {"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__},
{"dup", posix_dup, METH_VARARGS, posix_dup__doc__}, {"dup", posix_dup, METH_VARARGS, posix_dup__doc__},
{"dup2", posix_dup2, METH_VARARGS, posix_dup2__doc__}, {"dup2", (PyCFunction)posix_dup2,
METH_VARARGS | METH_KEYWORDS, posix_dup2__doc__},
#ifdef HAVE_LOCKF #ifdef HAVE_LOCKF
{"lockf", posix_lockf, METH_VARARGS, posix_lockf__doc__}, {"lockf", posix_lockf, METH_VARARGS, posix_lockf__doc__},
#endif #endif
@ -11105,6 +11356,14 @@ static PyMethodDef posix_methods[] = {
#endif #endif
{"cpu_count", (PyCFunction)posix_cpu_count, {"cpu_count", (PyCFunction)posix_cpu_count,
METH_NOARGS, posix_cpu_count__doc__}, 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__},
#ifdef MS_WINDOWS
{"get_handle_inheritable", posix_get_handle_inheritable,
METH_VARARGS, get_handle_inheritable__doc__},
{"set_handle_inheritable", posix_set_handle_inheritable,
METH_VARARGS, set_handle_inheritable__doc__},
#endif
{NULL, NULL} /* Sentinel */ {NULL, NULL} /* Sentinel */
}; };

View file

@ -1004,7 +1004,7 @@ newDevPollObject(void)
*/ */
limit_result = getrlimit(RLIMIT_NOFILE, &limit); limit_result = getrlimit(RLIMIT_NOFILE, &limit);
if (limit_result != -1) if (limit_result != -1)
fd_devpoll = open("/dev/poll", O_RDWR); fd_devpoll = _Py_open("/dev/poll", O_RDWR);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (limit_result == -1) { if (limit_result == -1) {
@ -1194,6 +1194,7 @@ newPyEpoll_Object(PyTypeObject *type, int sizehint, int flags, SOCKET fd)
if (fd == -1) { if (fd == -1) {
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_EPOLL_CREATE1 #ifdef HAVE_EPOLL_CREATE1
flags |= EPOLL_CLOEXEC;
if (flags) if (flags)
self->epfd = epoll_create1(flags); self->epfd = epoll_create1(flags);
else else
@ -1209,6 +1210,14 @@ newPyEpoll_Object(PyTypeObject *type, int sizehint, int flags, SOCKET fd)
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
#ifndef HAVE_EPOLL_CREATE1
if (_Py_set_inheritable(self->epfd, 0, NULL) < 0) {
Py_DECREF(self);
return NULL;
}
#endif
return (PyObject *)self; return (PyObject *)self;
} }
@ -1896,13 +1905,19 @@ newKqueue_Object(PyTypeObject *type, SOCKET fd)
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
if (fd == -1) {
if (_Py_set_inheritable(self->kqfd, 0, NULL) < 0) {
Py_DECREF(self);
return NULL;
}
}
return (PyObject *)self; return (PyObject *)self;
} }
static PyObject * static PyObject *
kqueue_queue_new(PyTypeObject *type, PyObject *args, PyObject *kwds) kqueue_queue_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
if ((args != NULL && PyObject_Size(args)) || if ((args != NULL && PyObject_Size(args)) ||
(kwds != NULL && PyObject_Size(kwds))) { (kwds != NULL && PyObject_Size(kwds))) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,

View file

@ -97,13 +97,14 @@ Local naming conventions:
/* Socket object documentation */ /* Socket object documentation */
PyDoc_STRVAR(sock_doc, PyDoc_STRVAR(sock_doc,
"socket([family[, type[, proto]]]) -> socket object\n\ "socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) -> socket object\n\
\n\ \n\
Open a socket of the given type. The family argument specifies the\n\ Open a socket of the given type. The family argument specifies the\n\
address family; it defaults to AF_INET. The type argument specifies\n\ address family; it defaults to AF_INET. The type argument specifies\n\
whether this is a stream (SOCK_STREAM, this is the default)\n\ whether this is a stream (SOCK_STREAM, this is the default)\n\
or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0,\n\ or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0,\n\
specifying the default protocol. Keyword arguments are accepted.\n\ specifying the default protocol. Keyword arguments are accepted.\n\
The socket is created as non-inheritable.\n\
\n\ \n\
A socket object represents one endpoint of a network connection.\n\ A socket object represents one endpoint of a network connection.\n\
\n\ \n\
@ -114,7 +115,7 @@ bind(addr) -- bind the socket to a local address\n\
close() -- close the socket\n\ close() -- close the socket\n\
connect(addr) -- connect the socket to a remote address\n\ connect(addr) -- connect the socket to a remote address\n\
connect_ex(addr) -- connect, return an error code instead of an exception\n\ connect_ex(addr) -- connect, return an error code instead of an exception\n\
_dup() -- return a new socket fd duplicated from fileno()\n\ dup() -- return a new socket fd duplicated from fileno()\n\
fileno() -- return underlying file descriptor\n\ fileno() -- return underlying file descriptor\n\
getpeername() -- return remote address [*]\n\ getpeername() -- return remote address [*]\n\
getsockname() -- return local address\n\ getsockname() -- return local address\n\
@ -356,22 +357,7 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
#endif #endif
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
/* On Windows a socket is really a handle not an fd */
static SOCKET
dup_socket(SOCKET handle)
{
WSAPROTOCOL_INFO info;
if (WSADuplicateSocket(handle, GetCurrentProcessId(), &info))
return INVALID_SOCKET;
return WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, &info, 0, WSA_FLAG_OVERLAPPED);
}
#define SOCKETCLOSE closesocket #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 #endif
#ifdef MS_WIN32 #ifdef MS_WIN32
@ -499,6 +485,11 @@ select_error(void)
(errno == expected) (errno == expected)
#endif #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 /* Convenience function to raise an error according to errno
and return a NULL pointer from a function. */ and return a NULL pointer from a function. */
@ -1955,6 +1946,11 @@ sock_accept(PySocketSockObject *s)
PyObject *addr = NULL; PyObject *addr = NULL;
PyObject *res = NULL; PyObject *res = NULL;
int timeout; int timeout;
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
static int accept4_works = -1;
#endif
if (!getsockaddrlen(s, &addrlen)) if (!getsockaddrlen(s, &addrlen))
return NULL; return NULL;
memset(&addrbuf, 0, addrlen); memset(&addrbuf, 0, addrlen);
@ -1963,10 +1959,24 @@ sock_accept(PySocketSockObject *s)
return select_error(); return select_error();
BEGIN_SELECT_LOOP(s) BEGIN_SELECT_LOOP(s)
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
timeout = internal_select_ex(s, 0, interval); timeout = internal_select_ex(s, 0, interval);
if (!timeout) { if (!timeout) {
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
if (accept4_works != 0) {
newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen,
SOCK_CLOEXEC);
if (newfd == INVALID_SOCKET && accept4_works == -1) {
/* On Linux older than 2.6.28, accept4() fails with ENOSYS */
accept4_works = (errno != ENOSYS);
}
}
if (accept4_works == 0)
newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
#else
newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
#endif
} }
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
@ -1979,6 +1989,25 @@ sock_accept(PySocketSockObject *s)
if (newfd == INVALID_SOCKET) if (newfd == INVALID_SOCKET)
return s->errorhandler(); return s->errorhandler();
#ifdef MS_WINDOWS
if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) {
PyErr_SetFromWindowsErr(0);
SOCKETCLOSE(newfd);
goto finally;
}
#else
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
if (!accept4_works)
#endif
{
if (_Py_set_inheritable(newfd, 0, NULL) < 0) {
SOCKETCLOSE(newfd);
goto finally;
}
}
#endif
sock = PyLong_FromSocket_t(newfd); sock = PyLong_FromSocket_t(newfd);
if (sock == NULL) { if (sock == NULL) {
SOCKETCLOSE(newfd); SOCKETCLOSE(newfd);
@ -3909,6 +3938,12 @@ sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
/* Initialize a new socket object. */ /* 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*/ /*ARGSUSED*/
static int static int
sock_initobj(PyObject *self, PyObject *args, PyObject *kwds) sock_initobj(PyObject *self, PyObject *args, PyObject *kwds)
@ -3918,6 +3953,13 @@ sock_initobj(PyObject *self, PyObject *args, PyObject *kwds)
SOCKET_T fd = INVALID_SOCKET; SOCKET_T fd = INVALID_SOCKET;
int family = AF_INET, type = SOCK_STREAM, proto = 0; int family = AF_INET, type = SOCK_STREAM, proto = 0;
static char *keywords[] = {"family", "type", "proto", "fileno", 0}; static char *keywords[] = {"family", "type", "proto", "fileno", 0};
#ifndef MS_WINDOWS
#ifdef SOCK_CLOEXEC
int *atomic_flag_works = &sock_cloexec_works;
#else
int *atomic_flag_works = NULL;
#endif
#endif
if (!PyArg_ParseTupleAndKeywords(args, kwds, if (!PyArg_ParseTupleAndKeywords(args, kwds,
"|iiiO:socket", keywords, "|iiiO:socket", keywords,
@ -3962,14 +4004,74 @@ sock_initobj(PyObject *self, PyObject *args, PyObject *kwds)
} }
} }
else { else {
#ifdef MS_WINDOWS
/* Windows implementation */
#ifndef WSA_FLAG_NO_HANDLE_INHERIT
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
#endif
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
fd = socket(family, type, proto); if (support_wsa_no_inherit) {
fd = WSASocket(family, type, proto,
NULL, 0,
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);
if (fd == INVALID_SOCKET) {
/* Windows 7 or Windows 2008 R2 without SP1 or the hotfix */
support_wsa_no_inherit = 0;
fd = socket(family, type, proto);
}
}
else {
fd = socket(family, type, proto);
}
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (fd == INVALID_SOCKET) { if (fd == INVALID_SOCKET) {
set_error(); set_error();
return -1; return -1;
} }
if (!support_wsa_no_inherit) {
if (!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0)) {
closesocket(fd);
PyErr_SetFromWindowsErr(0);
return -1;
}
}
#else
/* UNIX */
Py_BEGIN_ALLOW_THREADS
#ifdef SOCK_CLOEXEC
if (sock_cloexec_works != 0) {
fd = socket(family, type | SOCK_CLOEXEC, proto);
if (sock_cloexec_works == -1) {
if (fd >= 0) {
sock_cloexec_works = 1;
}
else if (errno == EINVAL) {
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */
sock_cloexec_works = 0;
fd = socket(family, type, proto);
}
}
}
else
#endif
{
fd = socket(family, type, proto);
}
Py_END_ALLOW_THREADS
if (fd == INVALID_SOCKET) {
set_error();
return -1;
}
if (_Py_set_inheritable(fd, 0, atomic_flag_works) < 0) {
SOCKETCLOSE(fd);
return -1;
}
#endif
} }
init_sockobject(s, fd, family, type, proto); init_sockobject(s, fd, family, type, proto);
@ -4535,16 +4637,36 @@ socket_dup(PyObject *self, PyObject *fdobj)
{ {
SOCKET_T fd, newfd; SOCKET_T fd, newfd;
PyObject *newfdobj; PyObject *newfdobj;
#ifdef MS_WINDOWS
WSAPROTOCOL_INFO info;
#endif
fd = PyLong_AsSocket_t(fdobj); fd = PyLong_AsSocket_t(fdobj);
if (fd == (SOCKET_T)(-1) && PyErr_Occurred()) if (fd == (SOCKET_T)(-1) && PyErr_Occurred())
return NULL; return NULL;
newfd = dup_socket(fd); #ifdef MS_WINDOWS
if (WSADuplicateSocket(fd, GetCurrentProcessId(), &info))
return set_error();
newfd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
&info, 0, WSA_FLAG_OVERLAPPED);
if (newfd == INVALID_SOCKET) if (newfd == INVALID_SOCKET)
return set_error(); return set_error();
if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) {
closesocket(newfd);
PyErr_SetFromWindowsErr(0);
return NULL;
}
#else
/* On UNIX, dup can be used to duplicate the file descriptor of a socket */
newfd = _Py_dup(fd);
if (newfd == INVALID_SOCKET)
return NULL;
#endif
newfdobj = PyLong_FromSocket_t(newfd); newfdobj = PyLong_FromSocket_t(newfd);
if (newfdobj == NULL) if (newfdobj == NULL)
SOCKETCLOSE(newfd); SOCKETCLOSE(newfd);
@ -4572,6 +4694,12 @@ socket_socketpair(PyObject *self, PyObject *args)
SOCKET_T sv[2]; SOCKET_T sv[2];
int family, type = SOCK_STREAM, proto = 0; int family, type = SOCK_STREAM, proto = 0;
PyObject *res = NULL; PyObject *res = NULL;
#ifdef SOCK_CLOEXEC
int *atomic_flag_works = &sock_cloexec_works;
#else
int *atomic_flag_works = NULL;
#endif
int ret;
#if defined(AF_UNIX) #if defined(AF_UNIX)
family = AF_UNIX; family = AF_UNIX;
@ -4581,9 +4709,38 @@ socket_socketpair(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "|iii:socketpair", if (!PyArg_ParseTuple(args, "|iii:socketpair",
&family, &type, &proto)) &family, &type, &proto))
return NULL; return NULL;
/* Create a pair of socket fds */ /* Create a pair of socket fds */
if (socketpair(family, type, proto, sv) < 0) Py_BEGIN_ALLOW_THREADS
#ifdef SOCK_CLOEXEC
if (sock_cloexec_works != 0) {
ret = socketpair(family, type | SOCK_CLOEXEC, proto, sv);
if (sock_cloexec_works == -1) {
if (ret >= 0) {
sock_cloexec_works = 1;
}
else if (errno == EINVAL) {
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */
sock_cloexec_works = 0;
ret = socketpair(family, type, proto, sv);
}
}
}
else
#endif
{
ret = socketpair(family, type, proto, sv);
}
Py_END_ALLOW_THREADS
if (ret < 0)
return set_error(); return set_error();
if (_Py_set_inheritable(sv[0], 0, atomic_flag_works) < 0)
goto finally;
if (_Py_set_inheritable(sv[1], 0, atomic_flag_works) < 0)
goto finally;
s0 = new_sockobject(sv[0], family, type, proto); s0 = new_sockobject(sv[0], family, type, proto);
if (s0 == NULL) if (s0 == NULL)
goto finally; goto finally;
@ -4605,7 +4762,7 @@ finally:
} }
PyDoc_STRVAR(socketpair_doc, PyDoc_STRVAR(socketpair_doc,
"socketpair([family[, type[, proto]]]) -> (socket object, socket object)\n\ "socketpair([family[, type [, proto]]]) -> (socket object, socket object)\n\
\n\ \n\
Create a pair of socket objects from the sockets returned by the platform\n\ Create a pair of socket objects from the sockets returned by the platform\n\
socketpair() function.\n\ socketpair() function.\n\
@ -5539,6 +5696,16 @@ PyInit__socket(void)
if (!os_init()) if (!os_init())
return NULL; return NULL;
#ifdef MS_WINDOWS
if (support_wsa_no_inherit == -1) {
DWORD version = GetVersion();
DWORD major = (DWORD)LOBYTE(LOWORD(version));
DWORD minor = (DWORD)HIBYTE(LOWORD(version));
/* need Windows 7 SP1, 2008 R2 SP1 or later */
support_wsa_no_inherit = (major >= 6 && minor >= 1);
}
#endif
Py_TYPE(&sock_type) = &PyType_Type; Py_TYPE(&sock_type) = &PyType_Type;
m = PyModule_Create(&socketmodule); m = PyModule_Create(&socketmodule);
if (m == NULL) if (m == NULL)

View file

@ -870,7 +870,7 @@ read_directory(PyObject *archive)
const char *charset; const char *charset;
int bootstrap; int bootstrap;
fp = _Py_fopen(archive, "rb"); fp = _Py_fopen_obj(archive, "rb");
if (fp == NULL) { if (fp == NULL) {
if (!PyErr_Occurred()) if (!PyErr_Occurred())
PyErr_Format(ZipImportError, "can't open Zip file: %R", archive); PyErr_Format(ZipImportError, "can't open Zip file: %R", archive);
@ -1064,7 +1064,7 @@ get_data(PyObject *archive, PyObject *toc_entry)
return NULL; return NULL;
} }
fp = _Py_fopen(archive, "rb"); fp = _Py_fopen_obj(archive, "rb");
if (!fp) { if (!fp) {
if (!PyErr_Occurred()) if (!PyErr_Occurred())
PyErr_Format(PyExc_IOError, PyErr_Format(PyExc_IOError,

View file

@ -55,7 +55,7 @@ static FNFCIFREE(cb_free)
static FNFCIOPEN(cb_open) static FNFCIOPEN(cb_open)
{ {
int result = _open(pszFile, oflag, pmode); int result = _open(pszFile, oflag | O_NOINHERIT, pmode);
if (result == -1) if (result == -1)
*err = errno; *err = errno;
return result; return result;
@ -179,7 +179,7 @@ static FNFCIGETOPENINFO(cb_getopeninfo)
CloseHandle(handle); CloseHandle(handle);
return _open(pszName, _O_RDONLY | _O_BINARY); return _open(pszName, _O_RDONLY | _O_BINARY | O_NOINHERIT);
} }
static PyObject* fcicreate(PyObject* obj, PyObject* args) static PyObject* fcicreate(PyObject* obj, PyObject* args)

View file

@ -743,7 +743,7 @@ do_run_installscript(HINSTANCE hPython, char *pathname, int argc, char **argv)
if (pathname == NULL || pathname[0] == '\0') if (pathname == NULL || pathname[0] == '\0')
return 2; return 2;
fh = open(pathname, _O_RDONLY); fh = open(pathname, _O_RDONLY | O_NOINHERIT);
if (-1 == fh) { if (-1 == fh) {
fprintf(stderr, "Could not open postinstall-script %s\n", fprintf(stderr, "Could not open postinstall-script %s\n",
pathname); pathname);

View file

@ -1730,10 +1730,15 @@ PyTokenizer_FindEncodingFilename(int fd, PyObject *filename)
FILE *fp; FILE *fp;
char *p_start =NULL , *p_end =NULL , *encoding = NULL; char *p_start =NULL , *p_end =NULL , *encoding = NULL;
#ifndef PGEN
fd = _Py_dup(fd);
#else
fd = dup(fd); fd = dup(fd);
#endif
if (fd < 0) { if (fd < 0) {
return NULL; return NULL;
} }
fp = fdopen(fd, "r"); fp = fdopen(fd, "r");
if (fp == NULL) { if (fp == NULL) {
return NULL; return NULL;

View file

@ -1042,7 +1042,7 @@ PyErr_ProgramText(const char *filename, int lineno)
FILE *fp; FILE *fp;
if (filename == NULL || *filename == '\0' || lineno <= 0) if (filename == NULL || *filename == '\0' || lineno <= 0)
return NULL; return NULL;
fp = fopen(filename, "r" PY_STDIOTEXTMODE); fp = _Py_fopen(filename, "r" PY_STDIOTEXTMODE);
return err_programtext(fp, lineno); return err_programtext(fp, lineno);
} }
@ -1052,7 +1052,7 @@ PyErr_ProgramTextObject(PyObject *filename, int lineno)
FILE *fp; FILE *fp;
if (filename == NULL || lineno <= 0) if (filename == NULL || lineno <= 0)
return NULL; return NULL;
fp = _Py_fopen(filename, "r" PY_STDIOTEXTMODE); fp = _Py_fopen_obj(filename, "r" PY_STDIOTEXTMODE);
return err_programtext(fp, lineno); return err_programtext(fp, lineno);
} }

View file

@ -9,10 +9,29 @@
#include <langinfo.h> #include <langinfo.h>
#endif #endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */
#ifdef __APPLE__ #ifdef __APPLE__
extern wchar_t* _Py_DecodeUTF8_surrogateescape(const char *s, Py_ssize_t size); extern wchar_t* _Py_DecodeUTF8_surrogateescape(const char *s, Py_ssize_t size);
#endif #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 * PyObject *
_Py_device_encoding(int fd) _Py_device_encoding(int fd)
{ {
@ -547,14 +566,215 @@ _Py_stat(PyObject *path, struct stat *statbuf)
#endif #endif
/* Open a file. Use _wfopen() on Windows, encode the path to the locale int
encoding and use fopen() otherwise. */ get_inheritable(int fd, int raise)
{
#ifdef MS_WINDOWS
HANDLE handle;
DWORD flags;
if (!_PyVerify_fd(fd)) {
if (raise)
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
handle = (HANDLE)_get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
if (raise)
PyErr_SetFromWindowsErr(0);
return -1;
}
if (!GetHandleInformation(handle, &flags)) {
if (raise)
PyErr_SetFromWindowsErr(0);
return -1;
}
return (flags & HANDLE_FLAG_INHERIT);
#else
int flags;
flags = fcntl(fd, F_GETFD, 0);
if (flags == -1) {
if (raise)
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
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
HANDLE handle;
DWORD flags;
#elif defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)
int request;
int err;
#elif defined(HAVE_FCNTL_H)
int flags;
int res;
#endif
/* atomic_flag_works can only be used to make the file descriptor
non-inheritable */
assert(!(atomic_flag_works != NULL && inheritable));
if (atomic_flag_works != NULL && !inheritable) {
if (*atomic_flag_works == -1) {
int inheritable = get_inheritable(fd, raise);
if (inheritable == -1)
return -1;
*atomic_flag_works = !inheritable;
}
if (*atomic_flag_works)
return 0;
}
#ifdef MS_WINDOWS
if (!_PyVerify_fd(fd)) {
if (raise)
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
handle = (HANDLE)_get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
if (raise)
PyErr_SetFromWindowsErr(0);
return -1;
}
if (inheritable)
flags = HANDLE_FLAG_INHERIT;
else
flags = 0;
if (!SetHandleInformation(handle, HANDLE_FLAG_INHERIT, flags)) {
if (raise)
PyErr_SetFromWindowsErr(0);
return -1;
}
return 0;
#elif defined(HAVE_SYS_IOCTL_H) && defined(FIOCLEX) && defined(FIONCLEX)
if (inheritable)
request = FIONCLEX;
else
request = FIOCLEX;
err = ioctl(fd, request);
if (err) {
if (raise)
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
return 0;
#else
flags = fcntl(fd, F_GETFD);
if (flags < 0) {
if (raise)
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
if (inheritable)
flags &= ~FD_CLOEXEC;
else
flags |= FD_CLOEXEC;
res = fcntl(fd, F_SETFD, flags);
if (res < 0) {
if (raise)
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
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:
* if *atomic_flag_works==-1, check if the inheritable is set on the file
descriptor: if yes, set *atomic_flag_works to 1, otherwise set to 0 and
set the inheritable flag
* if *atomic_flag_works==1: do nothing
* if *atomic_flag_works==0: set inheritable flag to False
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;
#ifdef MS_WINDOWS
fd = open(pathname, flags | O_NOINHERIT);
if (fd < 0)
return fd;
#else
int *atomic_flag_works;
#ifdef O_CLOEXEC
atomic_flag_works = &_Py_open_cloexec_works;
flags |= O_CLOEXEC;
#else
atomic_flag_works = NULL;
#endif
fd = open(pathname, flags);
if (fd < 0)
return fd;
if (set_inheritable(fd, 0, 0, atomic_flag_works) < 0) {
close(fd);
return -1;
}
#endif /* !MS_WINDOWS */
return fd;
}
/* 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 * FILE *
_Py_wfopen(const wchar_t *path, const wchar_t *mode) _Py_wfopen(const wchar_t *path, const wchar_t *mode)
{ {
#ifndef MS_WINDOWS
FILE *f; FILE *f;
#ifndef MS_WINDOWS
char *cpath; char *cpath;
char cmode[10]; char cmode[10];
size_t r; size_t r;
@ -568,21 +788,42 @@ _Py_wfopen(const wchar_t *path, const wchar_t *mode)
return NULL; return NULL;
f = fopen(cpath, cmode); f = fopen(cpath, cmode);
PyMem_Free(cpath); PyMem_Free(cpath);
return f;
#else #else
return _wfopen(path, mode); f = _wfopen(path, mode);
#endif #endif
if (f == NULL)
return NULL;
if (make_non_inheritable(fileno(f)) < 0) {
fclose(f);
return NULL;
}
return f;
} }
/* Call _wfopen() on Windows, or encode the path to the filesystem encoding and /* Wrapper to fopen(). The file descriptor is created non-inheritable. */
call fopen() otherwise. FILE*
_Py_fopen(const char *pathname, const char *mode)
{
FILE *f = fopen(pathname, mode);
if (f == NULL)
return NULL;
if (make_non_inheritable(fileno(f)) < 0) {
fclose(f);
return NULL;
}
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 Return the new file object on success, or NULL if the file cannot be open or
(if PyErr_Occurred()) on unicode error */ (if PyErr_Occurred()) on unicode error. */
FILE* FILE*
_Py_fopen(PyObject *path, const char *mode) _Py_fopen_obj(PyObject *path, const char *mode)
{ {
FILE *f;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
wchar_t *wpath; wchar_t *wpath;
wchar_t wmode[10]; wchar_t wmode[10];
@ -602,16 +843,21 @@ _Py_fopen(PyObject *path, const char *mode)
if (usize == 0) if (usize == 0)
return NULL; return NULL;
return _wfopen(wpath, wmode); f = _wfopen(wpath, wmode);
#else #else
FILE *f;
PyObject *bytes; PyObject *bytes;
if (!PyUnicode_FSConverter(path, &bytes)) if (!PyUnicode_FSConverter(path, &bytes))
return NULL; return NULL;
f = fopen(PyBytes_AS_STRING(bytes), mode); f = fopen(PyBytes_AS_STRING(bytes), mode);
Py_DECREF(bytes); Py_DECREF(bytes);
return f;
#endif #endif
if (f == NULL)
return NULL;
if (make_non_inheritable(fileno(f)) < 0) {
fclose(f);
return NULL;
}
return f;
} }
#ifdef HAVE_READLINK #ifdef HAVE_READLINK
@ -729,3 +975,72 @@ _Py_wgetcwd(wchar_t *buf, size_t size)
#endif #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;
#endif
if (!_PyVerify_fd(fd)) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
#ifdef MS_WINDOWS
handle = (HANDLE)_get_osfhandle(fd);
if (handle == INVALID_HANDLE_VALUE) {
PyErr_SetFromWindowsErr(0);
return -1;
}
/* get the file type, ignore the error if it failed */
ftype = GetFileType(handle);
Py_BEGIN_ALLOW_THREADS
fd = dup(fd);
Py_END_ALLOW_THREADS
if (fd < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
/* Character files like console cannot be make non-inheritable */
if (ftype != FILE_TYPE_CHAR) {
if (_Py_set_inheritable(fd, 0, NULL) < 0) {
close(fd);
return -1;
}
}
#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);
return -1;
}
#else
Py_BEGIN_ALLOW_THREADS
fd = dup(fd);
Py_END_ALLOW_THREADS
if (fd < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
if (_Py_set_inheritable(fd, 0, NULL) < 0) {
close(fd);
return -1;
}
#endif
return fd;
}

View file

@ -1797,7 +1797,7 @@ imp_load_dynamic(PyObject *self, PyObject *args)
&name, PyUnicode_FSDecoder, &pathname, &fob)) &name, PyUnicode_FSDecoder, &pathname, &fob))
return NULL; return NULL;
if (fob != NULL) { if (fob != NULL) {
fp = _Py_fopen(pathname, "r"); fp = _Py_fopen_obj(pathname, "r");
if (fp == NULL) { if (fp == NULL) {
Py_DECREF(pathname); Py_DECREF(pathname);
if (!PyErr_Occurred()) if (!PyErr_Occurred())

View file

@ -1454,7 +1454,7 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
/* Try to run a pyc file. First, re-open in binary */ /* Try to run a pyc file. First, re-open in binary */
if (closeit) if (closeit)
fclose(fp); fclose(fp);
if ((pyc_fp = fopen(filename, "rb")) == NULL) { if ((pyc_fp = _Py_fopen(filename, "rb")) == NULL) {
fprintf(stderr, "python: Can't reopen .pyc file\n"); fprintf(stderr, "python: Can't reopen .pyc file\n");
goto done; goto done;
} }

View file

@ -101,7 +101,7 @@ dev_urandom_noraise(char *buffer, Py_ssize_t size)
assert (0 < size); assert (0 < size);
fd = open("/dev/urandom", O_RDONLY); fd = _Py_open("/dev/urandom", O_RDONLY);
if (fd < 0) if (fd < 0)
Py_FatalError("Failed to open /dev/urandom"); Py_FatalError("Failed to open /dev/urandom");
@ -134,7 +134,7 @@ dev_urandom_python(char *buffer, Py_ssize_t size)
return 0; return 0;
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
fd = open("/dev/urandom", O_RDONLY); fd = _Py_open("/dev/urandom", O_RDONLY);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (fd < 0) if (fd < 0)
{ {

2
configure vendored
View file

@ -10275,7 +10275,7 @@ fi
# checks for library functions # checks for library functions
for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat \ clock confstr ctermid dup3 execv faccessat fchmod fchmodat fchown fchownat \
fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \ fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
futimens futimes gai_strerror \ futimens futimes gai_strerror \
getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \ getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \

View file

@ -2807,7 +2807,7 @@ fi
# checks for library functions # checks for library functions
AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
clock confstr ctermid execv faccessat fchmod fchmodat fchown fchownat \ clock confstr ctermid dup3 execv faccessat fchmod fchmodat fchown fchownat \
fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \ fexecve fdopendir fork fpathconf fstatat ftime ftruncate futimesat \
futimens futimes gai_strerror \ futimens futimes gai_strerror \
getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \ getgrouplist getgroups getlogin getloadavg getpeername getpgid getpid \

View file

@ -193,6 +193,9 @@
/* Define to 1 if you have the `dup2' function. */ /* Define to 1 if you have the `dup2' function. */
#undef HAVE_DUP2 #undef HAVE_DUP2
/* Define to 1 if you have the `dup3' function. */
#undef HAVE_DUP3
/* Defined when any dynamic module loading is enabled. */ /* Defined when any dynamic module loading is enabled. */
#undef HAVE_DYNAMIC_LOADING #undef HAVE_DYNAMIC_LOADING