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