diff options
-rw-r--r-- | Lib/ssl.py | 24 | ||||
-rwxr-xr-x | Lib/test/regrtest.py | 1 | ||||
-rw-r--r-- | Lib/test/test_multiprocessing.py | 82 | ||||
-rw-r--r-- | Lib/test/test_ssl.py | 16 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/_multiprocessing/multiprocessing.c | 4 | ||||
-rw-r--r-- | Modules/socketmodule.c | 4 |
8 files changed, 91 insertions, 44 deletions
diff --git a/Lib/ssl.py b/Lib/ssl.py index 1b7416e2bb..914e749928 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -355,14 +355,6 @@ class SSLSocket(socket): else: return socket.sendto(self, data, flags_or_addr, addr) - def sendmsg(self, *args, **kwargs): - self._checkClosed() - if self._sslobj: - raise ValueError("sendmsg not allowed on instances of %s" % - self.__class__) - else: - return socket.sendmsg(self, *args, **kwargs) - def sendall(self, data, flags=0): self._checkClosed() if self._sslobj: @@ -421,22 +413,6 @@ class SSLSocket(socket): else: return socket.recvfrom_into(self, buffer, nbytes, flags) - def recvmsg(self, *args, **kwargs): - self._checkClosed() - if self._sslobj: - raise ValueError("recvmsg not allowed on instances of %s" % - self.__class__) - else: - return socket.recvmsg(self, *args, **kwargs) - - def recvmsg_into(self, *args, **kwargs): - self._checkClosed() - if self._sslobj: - raise ValueError("recvmsg_into not allowed on instances of %s" % - self.__class__) - else: - return socket.recvmsg_into(self, *args, **kwargs) - def pending(self): self._checkClosed() if self._sslobj: diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 214e430e05..ca63496bf8 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -577,7 +577,6 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, elif ok == FAILED: bad.append(test) elif ok == ENV_CHANGED: - bad.append(test) environment_changed.append(test) elif ok == SKIPPED: skipped.append(test) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py index 405fbd5256..7a7805d59f 100644 --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -35,7 +35,7 @@ import multiprocessing.managers import multiprocessing.heap import multiprocessing.pool -from multiprocessing import util +from multiprocessing import util, reduction try: from multiprocessing.sharedctypes import Value, copy @@ -43,6 +43,11 @@ try: except ImportError: HAS_SHAREDCTYPES = False +try: + import msvcrt +except ImportError: + msvcrt = None + # # # @@ -89,6 +94,11 @@ else: timeout = None return handle in _select([handle], [], [], timeout)[0] +try: + MAXFD = os.sysconf("SC_OPEN_MAX") +except: + MAXFD = 256 + # # Some tests require ctypes # @@ -1587,6 +1597,76 @@ class _TestConnection(BaseTestCase): self.assertRaises(ValueError, a.send_bytes, msg, 4, -1) + @classmethod + def _is_fd_assigned(cls, fd): + try: + os.fstat(fd) + except OSError as e: + if e.errno == errno.EBADF: + return False + raise + else: + return True + + @classmethod + def _writefd(cls, conn, data, create_dummy_fds=False): + if create_dummy_fds: + for i in range(0, 256): + if not cls._is_fd_assigned(i): + os.dup2(conn.fileno(), i) + fd = reduction.recv_handle(conn) + if msvcrt: + fd = msvcrt.open_osfhandle(fd, os.O_WRONLY) + os.write(fd, data) + os.close(fd) + + def test_fd_transfer(self): + if self.TYPE != 'processes': + self.skipTest("only makes sense with processes") + conn, child_conn = self.Pipe(duplex=True) + + p = self.Process(target=self._writefd, args=(child_conn, b"foo")) + p.start() + with open(test.support.TESTFN, "wb") as f: + fd = f.fileno() + if msvcrt: + fd = msvcrt.get_osfhandle(fd) + reduction.send_handle(conn, fd, p.pid) + p.join() + with open(test.support.TESTFN, "rb") as f: + self.assertEqual(f.read(), b"foo") + + @unittest.skipIf(sys.platform == "win32", + "test semantics don't make sense on Windows") + @unittest.skipIf(MAXFD <= 256, + "largest assignable fd number is too small") + @unittest.skipUnless(hasattr(os, "dup2"), + "test needs os.dup2()") + def test_large_fd_transfer(self): + # With fd > 256 (issue #11657) + if self.TYPE != 'processes': + self.skipTest("only makes sense with processes") + conn, child_conn = self.Pipe(duplex=True) + + p = self.Process(target=self._writefd, args=(child_conn, b"bar", True)) + p.start() + with open(test.support.TESTFN, "wb") as f: + fd = f.fileno() + for newfd in range(256, MAXFD): + if not self._is_fd_assigned(newfd): + break + else: + self.fail("could not find an unassigned large file descriptor") + os.dup2(fd, newfd) + try: + reduction.send_handle(conn, newfd, p.pid) + finally: + os.close(newfd) + p.join() + with open(test.support.TESTFN, "rb") as f: + self.assertEqual(f.read(), b"bar") + + class _TestListenerClient(BaseTestCase): ALLOWED_TYPES = ('processes', 'threads') diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 1d26c11ed8..f3f0c54459 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -186,11 +186,8 @@ class BasicSocketTests(unittest.TestCase): self.assertRaises(socket.error, ss.recv_into, bytearray(b'x')) self.assertRaises(socket.error, ss.recvfrom, 1) self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1) - self.assertRaises(socket.error, ss.recvmsg, 1) - self.assertRaises(socket.error, ss.recvmsg_into, [bytearray(b'x')]) self.assertRaises(socket.error, ss.send, b'x') self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0)) - self.assertRaises(socket.error, ss.sendmsg, [b'x']) def test_timeout(self): # Issue #8524: when creating an SSL socket, the timeout of the @@ -1523,30 +1520,17 @@ else: count, addr = s.recvfrom_into(b) return b[:count] - def _recvmsg(*args, **kwargs): - return s.recvmsg(*args, **kwargs)[0] - - def _recvmsg_into(bufsize, *args, **kwargs): - b = bytearray(bufsize) - return bytes(b[:s.recvmsg_into([b], *args, **kwargs)[0]]) - - def _sendmsg(msg, *args, **kwargs): - return s.sendmsg([msg]) - # (name, method, whether to expect success, *args) send_methods = [ ('send', s.send, True, []), ('sendto', s.sendto, False, ["some.address"]), - ('sendmsg', _sendmsg, False, []), ('sendall', s.sendall, True, []), ] recv_methods = [ ('recv', s.recv, True, []), ('recvfrom', s.recvfrom, False, ["some.address"]), - ('recvmsg', _recvmsg, False, [100]), ('recv_into', _recv_into, True, []), ('recvfrom_into', _recvfrom_into, False, []), - ('recvmsg_into', _recvmsg_into, False, [100]), ] data_prefix = "PREFIX_" @@ -748,6 +748,7 @@ Zach Pincus Michael Piotrowski Antoine Pitrou Jean-François Piéronne +Remi Pointel Guilherme Polo Michael Pomraning Iustin Pop @@ -268,6 +268,9 @@ Core and Builtins Library ------- +- Issue #11657: Fix sending file descriptors over 255 over a multiprocessing + Pipe. + - Issue #12811: tabnanny.check() now promptly closes checked files. Patch by Anthony Briggs. diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c index 5d1cf5661a..1987b951f9 100644 --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -111,7 +111,7 @@ multiprocessing_sendfd(PyObject *self, PyObject *args) cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; - *CMSG_DATA(cmsg) = fd; + * (int *) CMSG_DATA(cmsg) = fd; Py_BEGIN_ALLOW_THREADS res = sendmsg(conn, &msg, 0); @@ -154,7 +154,7 @@ multiprocessing_recvfd(PyObject *self, PyObject *args) if (res < 0) return PyErr_SetFromErrno(PyExc_OSError); - fd = *CMSG_DATA(cmsg); + fd = * (int *) CMSG_DATA(cmsg); return Py_BuildValue("i", fd); } diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 81d1ce1070..5878ebb0d3 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -156,6 +156,10 @@ if_indextoname(index) -- return the corresponding interface name\n\ # undef HAVE_GETHOSTBYNAME_R_6_ARG #endif +#if defined(__OpenBSD__) +# include <sys/uio.h> +#endif + #ifndef WITH_THREAD # undef HAVE_GETHOSTBYNAME_R #endif |