"""Standalone copy of the regression test added by the patch. The patch adds this as TestDict.test_racing_dealloc_and_split_to_combined_resize in Lib/test/test_free_threading/test_dict.py. The standalone copy refuses to run with the GIL enabled (exit status 4), because it would then pass without testing anything. """ import sys import unittest from threading import Thread from test import support from test.support import threading_helper if getattr(sys, "_is_gil_enabled", lambda: True)(): sys.stderr.write("SKIP: needs a free-threaded build with the GIL disabled " "(sys._is_gil_enabled() is not False). Nothing tested.\n") sys.exit(4) @unittest.skipUnless(support.Py_GIL_DISABLED, "requires the free-threaded build") @threading_helper.requires_working_threading() class TestDict(unittest.TestCase): def test_racing_dealloc_and_split_to_combined_resize(self): # PyObject_ClearManagedDict() must not free an object while another # thread's dictresize() is still clearing the object's inline values # through its materialized __dict__. class C: def __init__(self): self.a0 = 0; self.a1 = 1; self.a2 = 2; self.a3 = 3 self.a4 = 4; self.a5 = 5; self.a6 = 6; self.a7 = 7 self.a8 = 8; self.a9 = 9; self.a10 = 10; self.a11 = 11 self.a12 = 12; self.a13 = 13; self.a14 = 14; self.a15 = 15 self.a16 = 16; self.a17 = 17; self.a18 = 18; self.a19 = 19 names = [f"a{i}" for i in range(20)] corrupted = [] def owner(slot): try: for j in range(100_000): o = C() for i, n in enumerate(names): if getattr(o, n, None) != i: corrupted.append((n, getattr(o, n, None))) return slot[0] = o.__dict__ # the dict escapes for _ in range(j % 16): # vary the timing of the dealloc pass del o # PyObject_ClearManagedDict() finally: slot[1] = True def converter(slot): while not slot[1]: d = slot[0] if d is not None: d[0] = 0 # non-str key: split -> combined dictresize() slot[0] = None threads = [] for _ in range(2): slot = [None, False] threads.append(Thread(target=owner, args=(slot,))) threads.append(Thread(target=converter, args=(slot,))) with threading_helper.start_threads(threads): pass self.assertEqual(corrupted, []) if __name__ == "__main__": unittest.main()