From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:01:00 +0000 (+0200) Subject: [3.15] gh-153932: protect read of en_index during enumerate.reduce (GH-154118) (GH... X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=fd6bd15c75955fee9cf2103d09de9e3c0f9fea5f;p=thirdparty%2FPython%2Fcpython.git [3.15] gh-153932: protect read of en_index during enumerate.reduce (GH-154118) (GH-154128) gh-153932: protect read of en_index during enumerate.reduce (GH-154118) (cherry picked from commit 1604043caf0a00fe4ea9f6e31e389c4cf8b8baab) Co-authored-by: L. Le --- diff --git a/Lib/test/libregrtest/tsan.py b/Lib/test/libregrtest/tsan.py index bacfe5e21ba0..c7ec63763bc9 100644 --- a/Lib/test/libregrtest/tsan.py +++ b/Lib/test/libregrtest/tsan.py @@ -8,6 +8,7 @@ TSAN_TESTS = [ 'test_ctypes', 'test_concurrent_futures', 'test_enum', + 'test_enumerate', 'test_functools', 'test_httpservers', 'test_imaplib', diff --git a/Lib/test/test_enumerate.py b/Lib/test/test_enumerate.py index 5cb54cff9b76..c8b85fe86921 100644 --- a/Lib/test/test_enumerate.py +++ b/Lib/test/test_enumerate.py @@ -3,8 +3,11 @@ import operator import sys import pickle import gc +import threading + from test import support +from test.support import threading_helper class G: 'Sequence using __getitem__' @@ -292,5 +295,28 @@ class TestLongStart(EnumerateStartTestCase): (sys.maxsize+3,'c')] +@threading_helper.requires_working_threading() +class TestThreadSafety(EnumerateStartTestCase): + def test_thread_safety_while_iterating(self): + # gh-153932: calling reduce while iterating should pass with TSAN + + en = enumerate(range(10_000)) + stop = threading.Event() + + def advance(): + for _ in en: + pass + stop.set() + + def read(): + while not stop.is_set(): + en.__reduce__() + + threads = [threading.Thread(target=advance), threading.Thread(target=read)] + + with threading_helper.start_threads(threads): + pass + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst new file mode 100644 index 000000000000..56b96307ed04 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-07-19-12-33-27.gh-issue-153932.lKw2bo.rst @@ -0,0 +1,2 @@ +Fix thread safety issue in the ``__reduce__`` method of +:py:class:`enumerate`. diff --git a/Objects/enumobject.c b/Objects/enumobject.c index fc53f1bfee8d..68aa594c5540 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -277,10 +277,13 @@ enum_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) enumobject *en = _enumobject_CAST(op); PyObject *result; Py_BEGIN_CRITICAL_SECTION(en); - if (en->en_longindex != NULL) + if (en->en_longindex != NULL) { result = Py_BuildValue("O(OO)", Py_TYPE(en), en->en_sit, en->en_longindex); - else - result = Py_BuildValue("O(On)", Py_TYPE(en), en->en_sit, en->en_index); + } + else { + Py_ssize_t en_index = FT_ATOMIC_LOAD_SSIZE_RELAXED(en->en_index); + result = Py_BuildValue("O(On)", Py_TYPE(en), en->en_sit, en_index); + } Py_END_CRITICAL_SECTION(); return result; }