From e4af342c3f4d8a243291d7cb450b00607bc61f95 Mon Sep 17 00:00:00 2001 From: lazerg Date: Mon, 28 Sep 2026 16:18:06 +0500 Subject: [PATCH] gh-158313: Clear the OpenSSL error queue when ssl raises OSError --- Lib/test/test_ssl.py | 30 +++++++++++++++++++ ...-09-28-11-17-55.gh-issue-158313.GbErga.rst | 3 ++ Modules/_ssl.c | 2 ++ 3 files changed, 35 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-09-28-11-17-55.gh-issue-158313.GbErga.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index abd7710a1d570a3..8ccb321d252d175 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -5197,6 +5197,36 @@ def test_got_eof(self): self.assertEqual(sslsock.pending(), 0) + def test_oserror_does_not_leak_to_other_sockets(self): + # gh-158313: An OSError for one connection must not stay on the + # thread's OpenSSL error queue and be raised for another connection. + client_context, server_context, hostname = testing_context() + server_context.num_tickets = 0 + + def connect(): + csock, ssock = socket.socketpair() + client = client_context.wrap_socket( + csock, server_hostname=hostname, do_handshake_on_connect=False) + server = server_context.wrap_socket( + ssock, server_side=True, do_handshake_on_connect=False) + thread = threading.Thread(target=server.do_handshake) + thread.start() + client.do_handshake() + thread.join() + return client, server + + client, server = connect() + client2, server2 = connect() + with client, server, client2, server2: + server.close() + client.settimeout(support.SHORT_TIMEOUT) + with self.assertRaises(OSError): + while True: + client.send(b'x' * 1024) + + client2.setblocking(False) + self.assertRaises(ssl.SSLWantReadError, client2.recv, 1) + @unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA, "Test needs TLS 1.3 PHA") diff --git a/Misc/NEWS.d/next/Library/2026-09-28-11-17-55.gh-issue-158313.GbErga.rst b/Misc/NEWS.d/next/Library/2026-09-28-11-17-55.gh-issue-158313.GbErga.rst new file mode 100644 index 000000000000000..25ff37dc72bf840 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-28-11-17-55.gh-issue-158313.GbErga.rst @@ -0,0 +1,3 @@ +Fix :mod:`ssl` leaving a system error on the OpenSSL error queue of the +thread after raising :exc:`OSError`, which made later I/O on other SSL +sockets in the same thread fail with the same error. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 4fd8bf0ac3b9579..8315f93fd6cc3e3 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -719,6 +719,7 @@ PySSL_SetError(PySSLSocket *sslsock, _PySSLError err, PyObject *exc, type = state->PySSLCertVerificationErrorObject; } if (ERR_GET_LIB(e) == ERR_LIB_SYS) { + ERR_clear_error(); // A system error is being reported; reason is set to errno errno = ERR_GET_REASON(e); return PyErr_SetFromErrno(PyExc_OSError); @@ -749,6 +750,7 @@ PySSL_SetError(PySSLSocket *sslsock, _PySSLError err, PyObject *exc, } #endif if (ERR_GET_LIB(e) == ERR_LIB_SYS) { + ERR_clear_error(); // A system error is being reported; reason is set to errno errno = ERR_GET_REASON(e); return PyErr_SetFromErrno(PyExc_OSError);