@@ -1533,19 +1533,24 @@ def dummycallback(sock, servername, ctx, cycle=ctx):
15331533 gc .collect ()
15341534 self .assertIs (wr (), None )
15351535
1536- @unittest .skipUnless (support .Py_GIL_DISABLED ,
1537- "test is only useful if the GIL is disabled" )
15381536 @threading_helper .requires_working_threading ()
15391537 def test_sni_callback_race (self ):
1540- # Replacing sni_callback while handshakes are in-flight must not
1538+ # Replacing sni_callback while a handshake is in-flight must not
15411539 # crash (use-after-free on the callback in free-threaded builds).
1540+ #
1541+ # Use a single handshake thread: OpenSSL has internal data races
1542+ # on shared SSL_CTX state when multiple handshakes run
1543+ # concurrently against the same context (gh-150191). Concurrency
1544+ # on the *setter* is what exercises the fix from gh-149816, so
1545+ # multiple toggler threads race against each other and against
1546+ # the one handshake worker.
15421547 client_ctx , server_ctx , hostname = testing_context ()
15431548
15441549 server_ctx .sni_callback = lambda * a : None
1545- done = threading . Event ()
1550+ deadline = time . monotonic () + 0.1
15461551
15471552 def do_handshakes ():
1548- while not done . is_set () :
1553+ while time . monotonic () < deadline :
15491554 c_in = ssl .MemoryBIO ()
15501555 c_out = ssl .MemoryBIO ()
15511556 s_in = ssl .MemoryBIO ()
@@ -1572,19 +1577,11 @@ def do_handshakes():
15721577 c_in .write (s_out .read ())
15731578
15741579 def toggle_callback ():
1575- while not done . is_set () :
1580+ while time . monotonic () < deadline :
15761581 server_ctx .sni_callback = lambda * a : None
15771582 server_ctx .sni_callback = None
15781583
1579- workers = max (4 , (os .cpu_count () or 4 ) * 2 )
1580- threads = [threading .Thread (target = do_handshakes )
1581- for _ in range (workers )]
1582- threads .append (threading .Thread (target = toggle_callback ))
1583-
1584- with threading_helper .catch_threading_exception () as cm :
1585- with threading_helper .start_threads (threads ):
1586- done .set ()
1587- self .assertIsNone (cm .exc_value )
1584+ threading_helper .run_concurrently ([do_handshakes ] + 4 * [toggle_callback ])
15881585
15891586 def test_cert_store_stats (self ):
15901587 ctx = ssl .SSLContext (ssl .PROTOCOL_TLS_CLIENT )
0 commit comments