Skip to content

Commit 47a4974

Browse files
committed
gh-151722: Move frozendict free-threading regression test into test_dict.py
1 parent 8a4795a commit 47a4974

2 files changed

Lines changed: 46 additions & 58 deletions

File tree

Lib/test/test_free_threading/test_dict.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from ast import Or
77
from functools import partial
8-
from threading import Barrier, Thread
8+
from threading import Barrier, Event, Thread
99
from unittest import TestCase
1010

1111
try:
@@ -336,5 +336,50 @@ def reader():
336336
with threading_helper.start_threads([t1, t2]):
337337
pass
338338

339+
def test_racing_frozendict_reads_during_construction(self):
340+
# gh-151722: a frozendict is GC-tracked before it is fully
341+
# populated, so a half-built instance is observable from other
342+
# threads. Reading it with len()/repr()/hash() must not race
343+
# with the construction-time table and ma_used writes.
344+
NUM_KEYS = 8192
345+
NUM_ROUNDS = 40
346+
347+
latest = [frozendict()] # main -> reader handoff, never empty
348+
done = Event()
349+
350+
class Evil:
351+
def keys(self):
352+
return [f"k{i}" for i in range(NUM_KEYS)]
353+
354+
def __getitem__(self, key):
355+
if latest[0] is empty:
356+
for obj in gc.get_objects():
357+
if (isinstance(obj, frozendict)
358+
and 0 < len(obj) < NUM_KEYS):
359+
latest[0] = obj # leak the half-built object
360+
break
361+
return 1
362+
363+
empty = latest[0]
364+
365+
def reader():
366+
while not done.is_set():
367+
fd = latest[0]
368+
len(fd)
369+
repr(fd)
370+
hash(fd)
371+
372+
readers = [Thread(target=reader) for _ in range(3)]
373+
for t in readers:
374+
t.start()
375+
try:
376+
for _ in range(NUM_ROUNDS):
377+
latest[0] = empty
378+
frozendict(Evil())
379+
finally:
380+
done.set()
381+
for t in readers:
382+
t.join()
383+
339384
if __name__ == "__main__":
340385
unittest.main()

Lib/test/test_free_threading/test_frozendict.py

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)