From 0388a23dbb4fb9aff541d27f0eca2287a1d88a9d Mon Sep 17 00:00:00 2001 From: Miguel Mendes Date: Mon, 3 May 2021 11:04:51 +0100 Subject: [PATCH 1/2] Fix multiprocessing Listener authkey bug --- Lib/multiprocessing/connection.py | 3 ++- Lib/test/_test_multiprocessing.py | 26 +++++++++++++++++++ .../2021-05-03-11-04-12.bpo-43952.Me7fJe.rst | 2 ++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2021-05-03-11-04-12.bpo-43952.Me7fJe.rst diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 510e4b5aba44a6..7e4ac958f13ca4 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -465,8 +465,9 @@ def accept(self): ''' if self._listener is None: raise OSError('listener is closed') + c = self._listener.accept() - if self._authkey: + if self._authkey is not None: deliver_challenge(c, self._authkey) answer_challenge(c, self._authkey) return c diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index fd3b4303f034c1..0a6da7a3f75b5b 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -3300,6 +3300,32 @@ def test_context(self): if self.TYPE == 'processes': self.assertRaises(OSError, l.accept) + def test_empty_authkey(self): + # bpo-43952: allow empty bytes as authkey + def handler(*args): + raise RuntimeError('Connection took too long...') + + def run(addr, authkey): + client = self.connection.Client(addr, authkey=authkey) + client.send(1729) + + timeout_in_s = 2 + key = b"" + + try: + # wait 2s so the test won't hang forever in case of regression + signal.signal(signal.SIGALRM, handler) + signal.alarm(timeout_in_s) + with self.connection.Listener(authkey=key) as listener: + threading.Thread(target=run, args=(listener.address, key)).start() + with listener.accept() as d: + self.assertEqual(d.recv(), 1729) + finally: + signal.alarm(0) + + if self.TYPE == 'processes': + self.assertRaises(OSError, listener.accept) + @unittest.skipUnless(util.abstract_sockets_supported, "test needs abstract socket support") def test_abstract_socket(self): diff --git a/Misc/NEWS.d/next/Library/2021-05-03-11-04-12.bpo-43952.Me7fJe.rst b/Misc/NEWS.d/next/Library/2021-05-03-11-04-12.bpo-43952.Me7fJe.rst new file mode 100644 index 00000000000000..e164619e44a301 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-05-03-11-04-12.bpo-43952.Me7fJe.rst @@ -0,0 +1,2 @@ +Fix :meth:`multiprocessing.connection.Listener.accept()` to accept empty bytes +as authkey. Not accepting empty bytes as key causes it to hang indefinitely. From 39d84034e405e9f358857dd2fafbfbf52cff23ba Mon Sep 17 00:00:00 2001 From: Miguel Mendes Date: Mon, 3 May 2021 12:05:55 +0100 Subject: [PATCH 2/2] Remove signal --- Lib/test/_test_multiprocessing.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 0a6da7a3f75b5b..daeda9a4d0d420 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -3309,19 +3309,12 @@ def run(addr, authkey): client = self.connection.Client(addr, authkey=authkey) client.send(1729) - timeout_in_s = 2 key = b"" - try: - # wait 2s so the test won't hang forever in case of regression - signal.signal(signal.SIGALRM, handler) - signal.alarm(timeout_in_s) - with self.connection.Listener(authkey=key) as listener: - threading.Thread(target=run, args=(listener.address, key)).start() - with listener.accept() as d: - self.assertEqual(d.recv(), 1729) - finally: - signal.alarm(0) + with self.connection.Listener(authkey=key) as listener: + threading.Thread(target=run, args=(listener.address, key)).start() + with listener.accept() as d: + self.assertEqual(d.recv(), 1729) if self.TYPE == 'processes': self.assertRaises(OSError, listener.accept)