From ea37c006a5f7f2c01c35a08422ed6ae2fe06a14d Mon Sep 17 00:00:00 2001 From: Jia Yu Date: Tue, 3 Nov 2026 00:43:21 -0800 Subject: [PATCH] test: read TLS session tickets before the stalled-send threads start The TLS variant of test_real_websocket_stalled_send_is_interrupted_by_close crashed the pytest process at random in CI (segmentation fault in peer.close(); seen on Python 3.13 and 3.14, WBC-1678). The test builds its websocket directly on a fresh TLS socket, so the server's TLS 1.3 session tickets are still unread when the websocket's reader thread and the test's sender start. OpenSSL handles them inside SSL_read. When that overlapped the sender's SSL_write and the socket was then aborted, freed memory was written: in a stress reproduction on Linux (OpenSSL 3.0.22) the writer crashed in memcpy under BIO_write. Reading the tickets on one thread first removed the crash in 18,000 aborts. A probe showed the overlap in 8 of 500 runs of the unchanged test on macOS, and in none after this change. A real connection reads the tickets during the websocket opening handshake, before any query is sent, so the driver's abort path is left as it is. --- tests/test_disconnect.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_disconnect.py b/tests/test_disconnect.py index f6da310..cade315 100644 --- a/tests/test_disconnect.py +++ b/tests/test_disconnect.py @@ -836,6 +836,17 @@ def test_real_websocket_stalled_send_is_interrupted_by_close(tls, tmp_path): local = client_context.wrap_socket(local, server_hostname="localhost") peer = peers.get(timeout=3) handshake.join(timeout=3) + # Read the server's TLS 1.3 session tickets before any thread starts, as + # the websocket opening handshake does on a real connection. OpenSSL + # handles them inside SSL_read; handling them while the sender below is + # in SSL_write, then aborting the socket, crashed the interpreter at + # random (WBC-1678). + local.setblocking(False) + try: + local.recv(1) + except ssl.SSLWantReadError: + pass + local.setblocking(True) protocol = ClientProtocol(parse_uri("ws://localhost"), state=State.OPEN) ws = ClientConnection(local, protocol) conn = Connection(ws)