Skip to content

Comments

gh-145142: Make str.maketrans safe under free-threading#145157

Open
VanshAgarwal24036 wants to merge 2 commits intopython:mainfrom
VanshAgarwal24036:gh-145142-dict-next-critical-section
Open

gh-145142: Make str.maketrans safe under free-threading#145157
VanshAgarwal24036 wants to merge 2 commits intopython:mainfrom
VanshAgarwal24036:gh-145142-dict-next-critical-section

Conversation

@VanshAgarwal24036
Copy link
Contributor

@VanshAgarwal24036 VanshAgarwal24036 commented Feb 23, 2026

Replace unsafe PyDict_Next iteration with snapshot iteration using PyDict_Items to avoid crashes when the input dict is mutated concurrently under free-threading.

Adds a regression test.

Copy link
Contributor

@colesbury colesbury left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments below

Comment on lines +8 to +9
@threading_helper.reap_threads
def test_maketrans_dict_concurrent_modification(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to test_free_threading/test_str.py and remove the @threading_helper.reap_threads -- it's not needed

}
PyObject *items = PyDict_Items(x);
if(items == NULL) goto err;
Py_ssize_t n = PyList_GET_SIZE(items);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a critical section here instead of copying the items to a list. You'll need to fix up the goto err. Something like:

{
    ...
    Py_BEGIN_CRITICAL_SECTION(x);
    while (PyDict_Next(x, &i, &key, &value)) {
        ...
    }
    goto done;
err:
    Py_CLEAR(new);
done:
    Py_END_CRITICAL_SECTION();
    return new;
}

@@ -0,0 +1,3 @@
Fix a crash in free-threaded builds when str.maketrans() iterates over a
dictionary that is concurrently modified. Wrap PyDict_Next iteration in a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix a crash in the free-threaded build when the dictionary argument to
:meth:`str.maketrans()` is concurrently modified.

We don't need to include implementation details about the critical section in the NEWS blurb.

def test_maketrans_dict_concurrent_modification(self):
number_of_iterations = 5
number_of_attempts = 100
for _ in range(number_of_iterations):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for _ in range(5):. Same with the loop below. Don't bother to assign the iteration count to local variables.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants