Skip to content

Commit e4af342

Browse files
committed
gh-158313: Clear the OpenSSL error queue when ssl raises OSError
1 parent 7352b6a commit e4af342

3 files changed

Lines changed: 35 additions & 0 deletions

File tree

‎Lib/test/test_ssl.py‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5197,6 +5197,36 @@ def test_got_eof(self):
51975197

51985198
self.assertEqual(sslsock.pending(), 0)
51995199

5200+
def test_oserror_does_not_leak_to_other_sockets(self):
5201+
# gh-158313: An OSError for one connection must not stay on the
5202+
# thread's OpenSSL error queue and be raised for another connection.
5203+
client_context, server_context, hostname = testing_context()
5204+
server_context.num_tickets = 0
5205+
5206+
def connect():
5207+
csock, ssock = socket.socketpair()
5208+
client = client_context.wrap_socket(
5209+
csock, server_hostname=hostname, do_handshake_on_connect=False)
5210+
server = server_context.wrap_socket(
5211+
ssock, server_side=True, do_handshake_on_connect=False)
5212+
thread = threading.Thread(target=server.do_handshake)
5213+
thread.start()
5214+
client.do_handshake()
5215+
thread.join()
5216+
return client, server
5217+
5218+
client, server = connect()
5219+
client2, server2 = connect()
5220+
with client, server, client2, server2:
5221+
server.close()
5222+
client.settimeout(support.SHORT_TIMEOUT)
5223+
with self.assertRaises(OSError):
5224+
while True:
5225+
client.send(b'x' * 1024)
5226+
5227+
client2.setblocking(False)
5228+
self.assertRaises(ssl.SSLWantReadError, client2.recv, 1)
5229+
52005230

52015231
@unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA,
52025232
"Test needs TLS 1.3 PHA")
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :mod:`ssl` leaving a system error on the OpenSSL error queue of the
2+
thread after raising :exc:`OSError`, which made later I/O on other SSL
3+
sockets in the same thread fail with the same error.

‎Modules/_ssl.c‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ PySSL_SetError(PySSLSocket *sslsock, _PySSLError err, PyObject *exc,
719719
type = state->PySSLCertVerificationErrorObject;
720720
}
721721
if (ERR_GET_LIB(e) == ERR_LIB_SYS) {
722+
ERR_clear_error();
722723
// A system error is being reported; reason is set to errno
723724
errno = ERR_GET_REASON(e);
724725
return PyErr_SetFromErrno(PyExc_OSError);
@@ -749,6 +750,7 @@ PySSL_SetError(PySSLSocket *sslsock, _PySSLError err, PyObject *exc,
749750
}
750751
#endif
751752
if (ERR_GET_LIB(e) == ERR_LIB_SYS) {
753+
ERR_clear_error();
752754
// A system error is being reported; reason is set to errno
753755
errno = ERR_GET_REASON(e);
754756
return PyErr_SetFromErrno(PyExc_OSError);

0 commit comments

Comments
 (0)