Skip to content

Commit ba3b9cd

Browse files
gh-157217: Add free-threading dir() race test
1 parent 60be5a2 commit ba3b9cd

1 file changed

Lines changed: 41 additions & 1 deletion

File tree

Lib/test/test_free_threading/test_type.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from threading import Barrier, Thread
66
from unittest import TestCase
77
import sys
8-
from test.support import import_helper, threading_helper
8+
from test.support import import_helper, threading_helper, Py_GIL_DISABLED
99

1010
_testinternalcapi = import_helper.import_module("_testinternalcapi")
1111

@@ -401,6 +401,46 @@ class B(A):
401401
with threading_helper.start_threads(threads):
402402
pass
403403

404+
@unittest.skipUnless(Py_GIL_DISABLED,
405+
"race only occurs on the free-threaded build")
406+
def test_dir_racing_class_dict_insert(self):
407+
# gh-157217: dir() iterated a mappingproxy of the class dict without
408+
# holding that dict's critical section. A concurrent insert into the
409+
# class dict (for example a lazy __annotations_cache__) then raised
410+
# RuntimeError: dictionary changed size during iteration.
411+
errors = []
412+
413+
class C:
414+
x: int
415+
416+
for i in range(200):
417+
setattr(C, f'attr_{i}', i)
418+
419+
def reader():
420+
barrier.wait()
421+
for _ in range(400):
422+
try:
423+
dir(C)
424+
dict(vars(C))
425+
{**vars(C)}
426+
except RuntimeError as exc:
427+
errors.append(exc)
428+
429+
def writer():
430+
barrier.wait()
431+
# First access stores __annotations_cache__ on the class.
432+
C.__annotations__
433+
for i in range(200):
434+
setattr(C, f'extra_{i}', i)
435+
436+
n_readers = 4
437+
barrier = threading.Barrier(n_readers + 1)
438+
threads = [Thread(target=reader) for _ in range(n_readers)]
439+
threads.append(Thread(target=writer))
440+
with threading_helper.start_threads(threads):
441+
pass
442+
self.assertEqual(errors, [])
443+
404444

405445
if __name__ == "__main__":
406446
unittest.main()

0 commit comments

Comments
 (0)