diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index abd7710a1d570a..8ccb321d252d17 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 00000000000000..25ff37dc72bf84 --- /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 4fd8bf0ac3b957..8315f93fd6cc3e 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);