Skip to content

str.maketrans on a mutating dict is not thread-safe #145142

@eendebakpt

Description

@eendebakpt

Crash report

What happened?

A reproducer (in the format of Lib/tests/test_free_threading/xxx.py):

import unittest
from test.support import threading_helper

threading_helper.requires_working_threading(module=True)


class ItertoolsThreading(unittest.TestCase):

    @threading_helper.reap_threads
    def test_maketrans(self):
        number_of_iterations = 10
        number_of_attempts=100
        for _ in range(number_of_iterations):
            print(f'iteration {_}')
            d = {2000: 'a'}
            def work_iterator(dct):
                for idx in range(number_of_attempts):
                    str.maketrans(dct)
                    idx = 2000 + idx # outside range of small ints
                    dct[idx] = chr(idx%16)
                    dct.pop(idx, None)
            threading_helper.run_concurrently(work_iterator, nthreads=10, args=[d])

if __name__ == "__main__":
    unittest.main()
    print('done')

At first glance it seems that the iteration using PyDict_Next is not safe (but maybe there are more unsafe parts):

while (PyDict_Next(x, &i, &key, &value)) {

(found when reviewing #145129)

CPython versions tested on:

CPython main branch

Operating systems tested on:

Windows

Output from running 'python -VV' on the command line:

No response

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    easyinterpreter-core(Objects, Python, Grammar, and Parser dirs)topic-free-threadingtype-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions