Skip to content

Commit b105157

Browse files
[3.13] gh-124984: Enhance ssl thread safety (GH-124993) (#125780)
Make SSL objects thread safe in Free Theaded build by using critical sections. (cherry picked from commit 4c53b25) Co-authored-by: Peter Bierma <[email protected]> Co-authored-by: Bénédikt Tran <[email protected]>
1 parent d9ac6b3 commit b105157

File tree

4 files changed

+1769
-316
lines changed

4 files changed

+1769
-316
lines changed

Lib/test/test_ssl.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import sys
44
import unittest
55
import unittest.mock
6+
from ast import literal_eval
7+
from threading import Thread
68
from test import support
79
from test.support import import_helper
810
from test.support import os_helper
@@ -304,11 +306,19 @@ def test_wrap_socket(sock, *,
304306
return context.wrap_socket(sock, **kwargs)
305307

306308

309+
USE_SAME_TEST_CONTEXT = False
310+
_TEST_CONTEXT = None
311+
307312
def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
308313
"""Create context
309314
310315
client_context, server_context, hostname = testing_context()
311316
"""
317+
global _TEST_CONTEXT
318+
if USE_SAME_TEST_CONTEXT:
319+
if _TEST_CONTEXT is not None:
320+
return _TEST_CONTEXT
321+
312322
if server_cert == SIGNED_CERTFILE:
313323
hostname = SIGNED_CERTFILE_HOSTNAME
314324
elif server_cert == SIGNED_CERTFILE2:
@@ -326,6 +336,10 @@ def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
326336
if server_chain:
327337
server_context.load_verify_locations(SIGNING_CA)
328338

339+
if USE_SAME_TEST_CONTEXT:
340+
if _TEST_CONTEXT is not None:
341+
_TEST_CONTEXT = client_context, server_context, hostname
342+
329343
return client_context, server_context, hostname
330344

331345

@@ -2834,6 +2848,44 @@ def test_echo(self):
28342848
'Cannot create a client socket with a PROTOCOL_TLS_SERVER context',
28352849
str(e.exception))
28362850

2851+
@unittest.skipUnless(support.Py_GIL_DISABLED, "test is only useful if the GIL is disabled")
2852+
def test_ssl_in_multiple_threads(self):
2853+
# See GH-124984: OpenSSL is not thread safe.
2854+
threads = []
2855+
2856+
global USE_SAME_TEST_CONTEXT
2857+
USE_SAME_TEST_CONTEXT = True
2858+
try:
2859+
for func in (
2860+
self.test_echo,
2861+
self.test_alpn_protocols,
2862+
self.test_getpeercert,
2863+
self.test_crl_check,
2864+
self.test_check_hostname_idn,
2865+
self.test_wrong_cert_tls12,
2866+
self.test_wrong_cert_tls13,
2867+
):
2868+
# Be careful with the number of threads here.
2869+
# Too many can result in failing tests.
2870+
for num in range(5):
2871+
with self.subTest(func=func, num=num):
2872+
threads.append(Thread(target=func))
2873+
2874+
with threading_helper.catch_threading_exception() as cm:
2875+
for thread in threads:
2876+
with self.subTest(thread=thread):
2877+
thread.start()
2878+
2879+
for thread in threads:
2880+
with self.subTest(thread=thread):
2881+
thread.join()
2882+
if cm.exc_value is not None:
2883+
# Some threads can skip their test
2884+
if not isinstance(cm.exc_value, unittest.SkipTest):
2885+
raise cm.exc_value
2886+
finally:
2887+
USE_SAME_TEST_CONTEXT = False
2888+
28372889
def test_getpeercert(self):
28382890
if support.verbose:
28392891
sys.stdout.write("\n")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed thread safety in :mod:`ssl` in the free-threaded build. OpenSSL operations are now protected by a per-object lock.

0 commit comments

Comments
 (0)