From db3a4d61325557097b28e59eab36b4867c00b8dc Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 25 May 2026 20:07:06 +0200 Subject: [PATCH 1/4] gh-149879: Fix test_ssl on Cygwin --- Lib/ssl.py | 3 +++ Lib/test/test_ssl.py | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py index 896db17baeb3db..b0d57537cbceb1 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -1053,6 +1053,9 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True, # the non-blocking dance regardless. Our raise when any data # is found means consuming the data is harmless. notconn_pre_handshake_data = self.recv(1) + except BlockingIOError: + # On Cygwin, recv(1) fails with BlockingIOError + notconn_pre_handshake_data = b'' except OSError as e: # EINVAL occurs for recv(1) on non-connected on unix sockets. if e.errno not in (errno.ENOTCONN, errno.EINVAL): diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 7f237276617152..a60e96053b86d1 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -638,6 +638,7 @@ def test_refcycle(self): del ss self.assertEqual(wr(), None) + @unittest.skipIf(sys.platform == 'cygwin', 'test hangs on Cygwin') def test_wrapped_unconnected(self): # Methods on an unconnected SSLSocket propagate the original # OSError raise by the underlying socket object. @@ -3631,7 +3632,7 @@ def test_wrong_cert_tls13(self): OSError, 'alert unknown ca|EOF occurred|TLSV1_ALERT_UNKNOWN_CA|' 'closed by the remote host|Connection reset by peer|' - 'Broken pipe' + 'Broken pipe|Software caused connection abort' ): # TLS 1.3 perform client cert exchange after handshake s.write(b'data') @@ -4585,6 +4586,8 @@ def test_client_sigalgs_mismatch(self): ssl.SSLError, # On handshake failures, some systems raise a ConnectionResetError. ConnectionResetError, + # On handshake failures, Cygwin raises ConnectionAbortedError. + ConnectionAbortedError, # On handshake failures, macOS may raise a BrokenPipeError. # See https://github.com/python/cpython/issues/139504. BrokenPipeError, @@ -5693,7 +5696,7 @@ def run(self): def non_linux_skip_if_other_okay_error(self, err): if sys.platform in ("linux", "android"): return # Expect the full test setup to always work on Linux. - if (isinstance(err, ConnectionResetError) or + if (isinstance(err, (ConnectionResetError, ConnectionAbortedError)) or (isinstance(err, OSError) and err.errno == errno.EINVAL) or re.search('wrong.version.number', str(getattr(err, "reason", "")), re.I) or re.search('record.layer.failure', str(getattr(err, "reason", "")), re.I) From bca7a45aa18ef12c0aa59da0710c878da408c9e8 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 25 May 2026 21:20:53 +0200 Subject: [PATCH 2/4] Avoid BlockingIOError, use EAGAIN instead --- Lib/ssl.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py index b0d57537cbceb1..5273d1d47ba915 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -1053,13 +1053,11 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True, # the non-blocking dance regardless. Our raise when any data # is found means consuming the data is harmless. notconn_pre_handshake_data = self.recv(1) - except BlockingIOError: - # On Cygwin, recv(1) fails with BlockingIOError - notconn_pre_handshake_data = b'' except OSError as e: # EINVAL occurs for recv(1) on non-connected on unix sockets. - if e.errno not in (errno.ENOTCONN, errno.EINVAL): - raise + # EAGAIN occurs on Cygwin. + if e.errno not in (errno.ENOTCONN, errno.EINVAL, + errno.EAGAIN): notconn_pre_handshake_data = b'' self.setblocking(blocking) if notconn_pre_handshake_data: From 8f84a293b7afbdc7d19eb213148e96e1df9f8973 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 25 May 2026 21:24:16 +0200 Subject: [PATCH 3/4] Fix merge mistake --- Lib/ssl.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/ssl.py b/Lib/ssl.py index 5273d1d47ba915..63776a704d1d85 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -1058,6 +1058,7 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True, # EAGAIN occurs on Cygwin. if e.errno not in (errno.ENOTCONN, errno.EINVAL, errno.EAGAIN): + raise notconn_pre_handshake_data = b'' self.setblocking(blocking) if notconn_pre_handshake_data: From 9b9ba2fc775f2707bb2a03f79a416d71314aaebe Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 25 May 2026 21:31:56 +0200 Subject: [PATCH 4/4] Only ignore EAGAIN on Cygwin --- Lib/ssl.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py index 63776a704d1d85..f23bcbe75e7201 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -1055,9 +1055,12 @@ def _create(cls, sock, server_side=False, do_handshake_on_connect=True, notconn_pre_handshake_data = self.recv(1) except OSError as e: # EINVAL occurs for recv(1) on non-connected on unix sockets. - # EAGAIN occurs on Cygwin. - if e.errno not in (errno.ENOTCONN, errno.EINVAL, - errno.EAGAIN): + if e.errno in (errno.ENOTCONN, errno.EINVAL): + pass + elif sys.platform == 'cygwin' and e.errno == errno.EAGAIN: + # EAGAIN occurs on Cygwin. + pass + else: raise notconn_pre_handshake_data = b'' self.setblocking(blocking)