@@ -1606,19 +1606,24 @@ def dummycallback(sock, servername, ctx, cycle=ctx):
16061606 gc .collect ()
16071607 self .assertIs (wr (), None )
16081608
1609- @unittest .skipUnless (support .Py_GIL_DISABLED ,
1610- "test is only useful if the GIL is disabled" )
16111609 @threading_helper .requires_working_threading ()
16121610 def test_sni_callback_race (self ):
1613- # Replacing sni_callback while handshakes are in-flight must not
1611+ # Replacing sni_callback while a handshake is in-flight must not
16141612 # crash (use-after-free on the callback in free-threaded builds).
1613+ #
1614+ # Use a single handshake thread: OpenSSL has internal data races
1615+ # on shared SSL_CTX state when multiple handshakes run
1616+ # concurrently against the same context (gh-150191). Concurrency
1617+ # on the *setter* is what exercises the fix from gh-149816, so
1618+ # multiple toggler threads race against each other and against
1619+ # the one handshake worker.
16151620 client_ctx , server_ctx , hostname = testing_context ()
16161621
16171622 server_ctx .sni_callback = lambda * a : None
1618- done = threading . Event ()
1623+ deadline = time . monotonic () + 0.1
16191624
16201625 def do_handshakes ():
1621- while not done . is_set () :
1626+ while time . monotonic () < deadline :
16221627 c_in = ssl .MemoryBIO ()
16231628 c_out = ssl .MemoryBIO ()
16241629 s_in = ssl .MemoryBIO ()
@@ -1645,19 +1650,11 @@ def do_handshakes():
16451650 c_in .write (s_out .read ())
16461651
16471652 def toggle_callback ():
1648- while not done . is_set () :
1653+ while time . monotonic () < deadline :
16491654 server_ctx .sni_callback = lambda * a : None
16501655 server_ctx .sni_callback = None
16511656
1652- workers = max (4 , (os .cpu_count () or 4 ) * 2 )
1653- threads = [threading .Thread (target = do_handshakes )
1654- for _ in range (workers )]
1655- threads .append (threading .Thread (target = toggle_callback ))
1656-
1657- with threading_helper .catch_threading_exception () as cm :
1658- with threading_helper .start_threads (threads ):
1659- done .set ()
1660- self .assertIsNone (cm .exc_value )
1657+ threading_helper .run_concurrently ([do_handshakes ] + 4 * [toggle_callback ])
16611658
16621659 def test_cert_store_stats (self ):
16631660 ctx = ssl .SSLContext (ssl .PROTOCOL_TLS_CLIENT )
0 commit comments