cpython/Lib/test/test_free_threading/test_pickle.py
Farhan Saif e62a61177f
gh-146452: Fix pickle segfault on concurrent mutation of dict in pickle (#146470)
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
2026-05-17 14:35:27 +05:30

44 lines
1.4 KiB
Python

import pickle
import threading
import unittest
from test.support import threading_helper
@threading_helper.requires_working_threading()
class TestPickleFreeThreading(unittest.TestCase):
def test_pickle_dumps_with_concurrent_dict_mutation(self):
# gh-146452: Pickling a dict while another thread mutates it
# used to segfault. batch_dict_exact() iterated dict items via
# PyDict_Next() which returns borrowed references, and a
# concurrent pop/replace could free the value before Py_INCREF
# got to it.
shared = {str(i): list(range(20)) for i in range(50)}
def dumper():
for _ in range(1000):
try:
pickle.dumps(shared)
except RuntimeError:
# "dictionary changed size during iteration" is expected
pass
def mutator():
for j in range(1000):
key = str(j % 50)
shared[key] = list(range(j % 20))
if j % 10 == 0:
shared.pop(key, None)
shared[key] = [j]
threads = []
for _ in range(10):
threads.append(threading.Thread(target=dumper))
threads.append(threading.Thread(target=mutator))
with threading_helper.start_threads(threads):
pass
if __name__ == "__main__":
unittest.main()