From 0745e4103aa899304e02b06d7b16a422a0b97e68 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 00:34:33 +0530 Subject: [PATCH 01/11] gh-145142: Make str.maketrans safe under free-threading --- .../test_maketrans_threading.py | 26 +++++++++++++++++++ ...-02-23-23-18-28.gh-issue-145142.T-XbVe.rst | 3 +++ Objects/unicodeobject.c | 9 ++++++- 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_free_threading/test_maketrans_threading.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst diff --git a/Lib/test/test_free_threading/test_maketrans_threading.py b/Lib/test/test_free_threading/test_maketrans_threading.py new file mode 100644 index 00000000000000..69b86aa15143a1 --- /dev/null +++ b/Lib/test/test_free_threading/test_maketrans_threading.py @@ -0,0 +1,26 @@ +import unittest +from test.support import threading_helper + +threading_helper.requires_working_threading(module=True) + + +class TestUnicodeFreeThreading(unittest.TestCase): + @threading_helper.reap_threads + def test_maketrans_dict_concurrent_modification(self): + number_of_iterations = 5 + number_of_attempts = 100 + for _ in range(number_of_iterations): + d = {2000: 'a'} + + def work_iterator(dct): + for i in range(number_of_attempts): + str.maketrans(dct) + idx = 2000 + i + dct[idx] = chr(idx % 16) + dct.pop(idx, None) + + threading_helper.run_concurrently( + work_iterator, + nthreads=5, + args=(d,), + ) \ No newline at end of file diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst new file mode 100644 index 00000000000000..045fc921b4f743 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst @@ -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 +critical section. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 988e5f95573fe1..6ba13e8154394b 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13154,8 +13154,14 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) "to maketrans it must be a dict"); goto err; } + PyObject *items = PyDict_Items(x); + if(items == NULL) goto err; + Py_ssize_t n = PyList_GET_SIZE(items); /* copy entries into the new dict, converting string keys to int keys */ - while (PyDict_Next(x, &i, &key, &value)) { + for (i = 0; i < n; i++) { + PyObject *pair = PyList_GET_ITEM(items, i); + key = PyTuple_GET_ITEM(pair, 0); + value = PyTuple_GET_ITEM(pair, 1); if (PyUnicode_Check(key)) { /* convert string keys to integer keys */ PyObject *newkey; @@ -13183,6 +13189,7 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) goto err; } } + Py_DECREF(items); } return new; err: From 3fdf54c694c0ffba7a466b8371e96ddc0b5cae97 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 00:38:40 +0530 Subject: [PATCH 02/11] Add new line at end of test file --- Lib/test/test_free_threading/test_maketrans_threading.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_free_threading/test_maketrans_threading.py b/Lib/test/test_free_threading/test_maketrans_threading.py index 69b86aa15143a1..5025431997af90 100644 --- a/Lib/test/test_free_threading/test_maketrans_threading.py +++ b/Lib/test/test_free_threading/test_maketrans_threading.py @@ -11,7 +11,7 @@ def test_maketrans_dict_concurrent_modification(self): number_of_attempts = 100 for _ in range(number_of_iterations): d = {2000: 'a'} - + def work_iterator(dct): for i in range(number_of_attempts): str.maketrans(dct) @@ -23,4 +23,4 @@ def work_iterator(dct): work_iterator, nthreads=5, args=(d,), - ) \ No newline at end of file + ) From 9a752459e913b688826a55eae40d021fa3d8a194 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 09:04:25 +0530 Subject: [PATCH 03/11] Update changes --- .../test_maketrans_threading.py | 26 ------------------- Lib/test/test_free_threading/test_str.py | 16 ++++++++++++ ...-02-23-23-18-28.gh-issue-145142.T-XbVe.rst | 5 ++-- Objects/unicodeobject.c | 26 +++++++++---------- 4 files changed, 31 insertions(+), 42 deletions(-) delete mode 100644 Lib/test/test_free_threading/test_maketrans_threading.py diff --git a/Lib/test/test_free_threading/test_maketrans_threading.py b/Lib/test/test_free_threading/test_maketrans_threading.py deleted file mode 100644 index 5025431997af90..00000000000000 --- a/Lib/test/test_free_threading/test_maketrans_threading.py +++ /dev/null @@ -1,26 +0,0 @@ -import unittest -from test.support import threading_helper - -threading_helper.requires_working_threading(module=True) - - -class TestUnicodeFreeThreading(unittest.TestCase): - @threading_helper.reap_threads - def test_maketrans_dict_concurrent_modification(self): - number_of_iterations = 5 - number_of_attempts = 100 - for _ in range(number_of_iterations): - d = {2000: 'a'} - - def work_iterator(dct): - for i in range(number_of_attempts): - str.maketrans(dct) - idx = 2000 + i - dct[idx] = chr(idx % 16) - dct.pop(idx, None) - - threading_helper.run_concurrently( - work_iterator, - nthreads=5, - args=(d,), - ) diff --git a/Lib/test/test_free_threading/test_str.py b/Lib/test/test_free_threading/test_str.py index 72044e979b0f48..9a1ce3620ac4b2 100644 --- a/Lib/test/test_free_threading/test_str.py +++ b/Lib/test/test_free_threading/test_str.py @@ -69,6 +69,22 @@ def reader_func(): for reader in readers: reader.join() + def test_maketrans_dict_concurrent_modification(self): + for _ in range(5): + d = {2000: 'a'} + + def work(dct): + for i in range(100): + str.maketrans(dct) + dct[2000 + i] = chr(i % 16) + dct.pop(2000 + i, None) + + threading_helper.run_concurrently( + work, + nthreads=5, + args=(d,), + ) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst index 045fc921b4f743..34e5a963006225 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst @@ -1,3 +1,2 @@ -Fix a crash in free-threaded builds when str.maketrans() iterates over a -dictionary that is concurrently modified. Wrap PyDict_Next iteration in a -critical section. +Fix a crash in the free-threaded build when the dictionary argument to +:meth:`str.maketrans()` is concurrently modified. \ No newline at end of file diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 6ba13e8154394b..a639c7fa45b942 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13154,42 +13154,42 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) "to maketrans it must be a dict"); goto err; } - PyObject *items = PyDict_Items(x); - if(items == NULL) goto err; - Py_ssize_t n = PyList_GET_SIZE(items); /* copy entries into the new dict, converting string keys to int keys */ - for (i = 0; i < n; i++) { - PyObject *pair = PyList_GET_ITEM(items, i); - key = PyTuple_GET_ITEM(pair, 0); - value = PyTuple_GET_ITEM(pair, 1); + Py_BEGIN_CRITICAL_SECTION(x); + while (PyDict_Next(x, &i, &key, &value)) { if (PyUnicode_Check(key)) { /* convert string keys to integer keys */ PyObject *newkey; if (PyUnicode_GET_LENGTH(key) != 1) { PyErr_SetString(PyExc_ValueError, "string keys in translate " "table must be of length 1"); - goto err; + goto err_in_cs; } kind = PyUnicode_KIND(key); data = PyUnicode_DATA(key); newkey = PyLong_FromLong(PyUnicode_READ(kind, data, 0)); if (!newkey) - goto err; + goto err_in_cs; res = PyDict_SetItem(new, newkey, value); Py_DECREF(newkey); if (res < 0) - goto err; + goto err_in_cs; } else if (PyLong_Check(key)) { /* just keep integer keys */ if (PyDict_SetItem(new, key, value) < 0) - goto err; + goto err_in_cs; } else { PyErr_SetString(PyExc_TypeError, "keys in translate table must " "be strings or integers"); - goto err; + goto err_in_cs; } } - Py_DECREF(items); + goto done; + err_in_cs: + Py_CLEAR(new); + done: + Py_END_CRITICAL_SECTION(); + return new; } return new; err: From 5071b9d4106a3f6ea96d4e740ef37f5dbb04ced0 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 09:07:43 +0530 Subject: [PATCH 04/11] Add new line at end of news file --- .../2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst index 34e5a963006225..9cf88a162a809e 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst @@ -1,2 +1,2 @@ Fix a crash in the free-threaded build when the dictionary argument to -:meth:`str.maketrans()` is concurrently modified. \ No newline at end of file +:meth:`str.maketrans()` is concurrently modified. From b34fd099f8f91fc6447f20e0a16f03e6988ec005 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 09:11:29 +0530 Subject: [PATCH 05/11] Remove unnecessary paranthesis in news file --- .../2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst index 9cf88a162a809e..5f6043cc3d9660 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-23-23-18-28.gh-issue-145142.T-XbVe.rst @@ -1,2 +1,2 @@ Fix a crash in the free-threaded build when the dictionary argument to -:meth:`str.maketrans()` is concurrently modified. +:meth:`str.maketrans` is concurrently modified. From 044c347f8a80162a2d0c03b85bd69399eb7357a1 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 09:24:50 +0530 Subject: [PATCH 06/11] Correct build error --- Objects/unicodeobject.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index a639c7fa45b942..3739c1d64912da 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13163,31 +13163,27 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) if (PyUnicode_GET_LENGTH(key) != 1) { PyErr_SetString(PyExc_ValueError, "string keys in translate " "table must be of length 1"); - goto err_in_cs; + return NULL; } kind = PyUnicode_KIND(key); data = PyUnicode_DATA(key); newkey = PyLong_FromLong(PyUnicode_READ(kind, data, 0)); if (!newkey) - goto err_in_cs; + return NULL; res = PyDict_SetItem(new, newkey, value); Py_DECREF(newkey); if (res < 0) - goto err_in_cs; + return NULL; } else if (PyLong_Check(key)) { /* just keep integer keys */ if (PyDict_SetItem(new, key, value) < 0) - goto err_in_cs; + return NULL; } else { PyErr_SetString(PyExc_TypeError, "keys in translate table must " "be strings or integers"); - goto err_in_cs; + return NULL; } } - goto done; - err_in_cs: - Py_CLEAR(new); - done: Py_END_CRITICAL_SECTION(); return new; } From b7e9d1b555d703b7b826b7ac50d2f9d9f9e75d5d Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 09:53:29 +0530 Subject: [PATCH 07/11] Update --- Objects/unicodeobject.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 3739c1d64912da..010692d6a15f0e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13163,27 +13163,31 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) if (PyUnicode_GET_LENGTH(key) != 1) { PyErr_SetString(PyExc_ValueError, "string keys in translate " "table must be of length 1"); - return NULL; + goto error; } kind = PyUnicode_KIND(key); data = PyUnicode_DATA(key); newkey = PyLong_FromLong(PyUnicode_READ(kind, data, 0)); if (!newkey) - return NULL; + goto error; res = PyDict_SetItem(new, newkey, value); Py_DECREF(newkey); if (res < 0) - return NULL; + goto error; } else if (PyLong_Check(key)) { /* just keep integer keys */ if (PyDict_SetItem(new, key, value) < 0) - return NULL; + goto error; } else { PyErr_SetString(PyExc_TypeError, "keys in translate table must " "be strings or integers"); - return NULL; + goto error; } } + goto done; + error: + Py_CLEAR(new); + done: Py_END_CRITICAL_SECTION(); return new; } From bfc812a07564c731572248cc666154ecebadaf07 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 18:04:04 +0530 Subject: [PATCH 08/11] Add new function --- Objects/unicodeobject.c | 85 +++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 010692d6a15f0e..246694406ace3e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13084,6 +13084,51 @@ character at the same position in y. If there is a third argument, it must be a string, whose characters will be mapped to None in the result. [clinic start generated code]*/ +static int +unicode_maketrans_from_dict(PyObject *x, PyObject *newdict) +{ + PyObject *key, *value; + Py_ssize_t i = 0; + int res; + + Py_BEGIN_CRITICAL_SECTION(x); + while (PyDict_Next(x, &i, &key, &value)) { + if (PyUnicode_Check(key)) { + PyObject *newkey; + int kind; + const void *data; + if (PyUnicode_GET_LENGTH(key) != 1) { + PyErr_SetString(PyExc_ValueError, "string keys in translate " + "table must be of length 1"); + goto error; + } + kind = PyUnicode_KIND(key); + data = PyUnicode_DATA(key); + newkey = PyLong_FromLong(PyUnicode_READ(kind, data, 0)); + if (!newkey) + goto error; + res = PyDict_SetItem(newdict, newkey, value); + Py_DECREF(newkey); + if(res < 0) + goto error; + } + else if (PyLong_Check(key)) { + if (PyDict_SetItem(newdict, key, value) < 0) + goto error; + } + else { + PyErr_SetString(PyExc_TypeError, "keys in translate table must " + "be strings or integers"); + goto error; + } + } + Py_END_CRITICAL_SECTION(); + return 0; + error: + Py_END_CRITICAL_SECTION(); + return -1; +} + static PyObject * unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) /*[clinic end generated code: output=a925c89452bd5881 input=7bfbf529a293c6c5]*/ @@ -13145,9 +13190,6 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) } } } else { - int kind; - const void *data; - /* x must be a dict */ if (!PyAnyDict_CheckExact(x)) { PyErr_SetString(PyExc_TypeError, "if you give only one argument " @@ -13155,41 +13197,8 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) goto err; } /* copy entries into the new dict, converting string keys to int keys */ - Py_BEGIN_CRITICAL_SECTION(x); - while (PyDict_Next(x, &i, &key, &value)) { - if (PyUnicode_Check(key)) { - /* convert string keys to integer keys */ - PyObject *newkey; - if (PyUnicode_GET_LENGTH(key) != 1) { - PyErr_SetString(PyExc_ValueError, "string keys in translate " - "table must be of length 1"); - goto error; - } - kind = PyUnicode_KIND(key); - data = PyUnicode_DATA(key); - newkey = PyLong_FromLong(PyUnicode_READ(kind, data, 0)); - if (!newkey) - goto error; - res = PyDict_SetItem(new, newkey, value); - Py_DECREF(newkey); - if (res < 0) - goto error; - } else if (PyLong_Check(key)) { - /* just keep integer keys */ - if (PyDict_SetItem(new, key, value) < 0) - goto error; - } else { - PyErr_SetString(PyExc_TypeError, "keys in translate table must " - "be strings or integers"); - goto error; - } - } - goto done; - error: - Py_CLEAR(new); - done: - Py_END_CRITICAL_SECTION(); - return new; + if(unicode_maketrans_from_dict(x, new) < 0) + goto err; } return new; err: From f7c3c45d8db11af1e7ef1289961ad94be1c62996 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 18:16:29 +0530 Subject: [PATCH 09/11] Update helper fuction --- Objects/unicodeobject.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 246694406ace3e..9611fb6404f6be 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13090,6 +13090,7 @@ unicode_maketrans_from_dict(PyObject *x, PyObject *newdict) PyObject *key, *value; Py_ssize_t i = 0; int res; + int ret = -1; /* assume failure */ Py_BEGIN_CRITICAL_SECTION(x); while (PyDict_Next(x, &i, &key, &value)) { @@ -13098,35 +13099,34 @@ unicode_maketrans_from_dict(PyObject *x, PyObject *newdict) int kind; const void *data; if (PyUnicode_GET_LENGTH(key) != 1) { - PyErr_SetString(PyExc_ValueError, "string keys in translate " + PyErr_SetString(PyExc_ValueError, "string keys in translate" "table must be of length 1"); - goto error; + goto done; } kind = PyUnicode_KIND(key); data = PyUnicode_DATA(key); newkey = PyLong_FromLong(PyUnicode_READ(kind, data, 0)); if (!newkey) - goto error; + goto done; res = PyDict_SetItem(newdict, newkey, value); Py_DECREF(newkey); - if(res < 0) - goto error; + if (res < 0) + goto done; } else if (PyLong_Check(key)) { if (PyDict_SetItem(newdict, key, value) < 0) - goto error; + goto done; } else { - PyErr_SetString(PyExc_TypeError, "keys in translate table must " + PyErr_SetString(PyExc_TypeError, "keys in translate table must" "be strings or integers"); - goto error; + goto done; } } + ret = 0; + done: Py_END_CRITICAL_SECTION(); - return 0; - error: - Py_END_CRITICAL_SECTION(); - return -1; + return ret; } static PyObject * From 4e715b009b73f76063db88741b415a0a355d7a37 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 21:22:54 +0530 Subject: [PATCH 10/11] Update function --- Objects/unicodeobject.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 9611fb6404f6be..c4f744b317c883 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13090,8 +13090,7 @@ unicode_maketrans_from_dict(PyObject *x, PyObject *newdict) PyObject *key, *value; Py_ssize_t i = 0; int res; - int ret = -1; /* assume failure */ - + int ret = -1; Py_BEGIN_CRITICAL_SECTION(x); while (PyDict_Next(x, &i, &key, &value)) { if (PyUnicode_Check(key)) { @@ -13101,30 +13100,31 @@ unicode_maketrans_from_dict(PyObject *x, PyObject *newdict) if (PyUnicode_GET_LENGTH(key) != 1) { PyErr_SetString(PyExc_ValueError, "string keys in translate" "table must be of length 1"); - goto done; + break; } kind = PyUnicode_KIND(key); data = PyUnicode_DATA(key); newkey = PyLong_FromLong(PyUnicode_READ(kind, data, 0)); if (!newkey) - goto done; + break; res = PyDict_SetItem(newdict, newkey, value); Py_DECREF(newkey); if (res < 0) - goto done; + break; } else if (PyLong_Check(key)) { if (PyDict_SetItem(newdict, key, value) < 0) - goto done; + break; } else { PyErr_SetString(PyExc_TypeError, "keys in translate table must" "be strings or integers"); - goto done; + break; } } - ret = 0; - done: + if (!PyErr_Occurred()) { + ret = 0; + } Py_END_CRITICAL_SECTION(); return ret; } From b60b67cc4406e5887b39e10e1e0346c9369e8a88 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 Date: Tue, 24 Feb 2026 23:57:05 +0530 Subject: [PATCH 11/11] Perform suggested changes --- Objects/unicodeobject.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index c4f744b317c883..6e132b1a7705ab 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13090,8 +13090,6 @@ unicode_maketrans_from_dict(PyObject *x, PyObject *newdict) PyObject *key, *value; Py_ssize_t i = 0; int res; - int ret = -1; - Py_BEGIN_CRITICAL_SECTION(x); while (PyDict_Next(x, &i, &key, &value)) { if (PyUnicode_Check(key)) { PyObject *newkey; @@ -13100,33 +13098,29 @@ unicode_maketrans_from_dict(PyObject *x, PyObject *newdict) if (PyUnicode_GET_LENGTH(key) != 1) { PyErr_SetString(PyExc_ValueError, "string keys in translate" "table must be of length 1"); - break; + return -1; } kind = PyUnicode_KIND(key); data = PyUnicode_DATA(key); newkey = PyLong_FromLong(PyUnicode_READ(kind, data, 0)); if (!newkey) - break; + return -1; res = PyDict_SetItem(newdict, newkey, value); Py_DECREF(newkey); if (res < 0) - break; + return -1; } else if (PyLong_Check(key)) { if (PyDict_SetItem(newdict, key, value) < 0) - break; + return -1; } else { PyErr_SetString(PyExc_TypeError, "keys in translate table must" "be strings or integers"); - break; + return -1; } } - if (!PyErr_Occurred()) { - ret = 0; - } - Py_END_CRITICAL_SECTION(); - return ret; + return 0; } static PyObject * @@ -13197,7 +13191,11 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) goto err; } /* copy entries into the new dict, converting string keys to int keys */ - if(unicode_maketrans_from_dict(x, new) < 0) + int errcode; + Py_BEGIN_CRITICAL_SECTION(x); + errcode = unicode_maketrans_from_dict(x, new); + Py_END_CRITICAL_SECTION(); + if (errcode < 0) goto err; } return new;