From 908a5906c2bf3729f5c7cde8713159760353288b Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Sat, 20 Dec 2025 17:52:47 +0530 Subject: [PATCH] fix more thread safety issues in list --- Lib/test/test_free_threading/test_list.py | 58 +++++++++++++++++++++++ Objects/listobject.c | 10 ++-- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_free_threading/test_list.py b/Lib/test/test_free_threading/test_list.py index 44c0ac74e02aa3..27ddc9c2d26dfb 100644 --- a/Lib/test/test_free_threading/test_list.py +++ b/Lib/test/test_free_threading/test_list.py @@ -91,6 +91,64 @@ def copy_back_and_forth(b, l): with threading_helper.start_threads(threads): pass + def test_reverse(self): + def reverse_list(b, l): + b.wait() + for _ in range(100): + l.reverse() + + def reader_list(b, l): + b.wait() + for _ in range(100): + for i in range(10): + self.assertTrue(0 <= l[i] < 10) + + l = list(range(10)) + barrier = Barrier(2) + threads = [Thread(target=reverse_list, args=(barrier, l)), + Thread(target=reader_list, args=(barrier, l))] + with threading_helper.start_threads(threads): + pass + + def test_slice_assignment1(self): + def assign_slice(b, l): + b.wait() + for _ in range(100): + l[2:5] = [7, 8, 9] + + def reader_list(b, l): + b.wait() + for _ in range(100): + self.assertIn(l[2], (2, 7)) + self.assertIn(l[3], (3, 8)) + self.assertIn(l[4], (4, 9)) + + l = list(range(10)) + barrier = Barrier(2) + threads = [Thread(target=assign_slice, args=(barrier, l)), + Thread(target=reader_list, args=(barrier, l))] + with threading_helper.start_threads(threads): + pass + + def test_slice_assignment2(self): + def assign_slice(b, l): + b.wait() + for _ in range(100): + l[::2] = [10, 11, 12, 13, 14] + + def reader_list(b, l): + b.wait() + for _ in range(100): + for i in range(0, 10, 2): + self.assertIn(l[i], (i, 10 + i // 2)) + + l = list(range(10)) + barrier = Barrier(2) + threads = [Thread(target=assign_slice, args=(barrier, l)), + Thread(target=reader_list, args=(barrier, l))] + with threading_helper.start_threads(threads): + pass + if __name__ == "__main__": unittest.main() diff --git a/Objects/listobject.c b/Objects/listobject.c index f67d1a45a494cb..4a98c8e54ab03f 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -501,7 +501,7 @@ ins1(PyListObject *self, Py_ssize_t where, PyObject *v) where = n; items = self->ob_item; for (i = n; --i >= where; ) - FT_ATOMIC_STORE_PTR_RELAXED(items[i+1], items[i]); + FT_ATOMIC_STORE_PTR_RELEASE(items[i+1], items[i]); FT_ATOMIC_STORE_PTR_RELEASE(items[where], Py_NewRef(v)); return 0; } @@ -1122,7 +1122,7 @@ list_ass_item_lock_held(PyListObject *a, Py_ssize_t i, PyObject *v) if (v == NULL) { Py_ssize_t size = Py_SIZE(a); for (Py_ssize_t idx = i; idx < size - 1; idx++) { - FT_ATOMIC_STORE_PTR_RELAXED(a->ob_item[idx], a->ob_item[idx + 1]); + FT_ATOMIC_STORE_PTR_RELEASE(a->ob_item[idx], a->ob_item[idx + 1]); } Py_SET_SIZE(a, size - 1); } @@ -1601,8 +1601,8 @@ reverse_slice(PyObject **lo, PyObject **hi) --hi; while (lo < hi) { PyObject *t = *lo; - *lo = *hi; - *hi = t; + FT_ATOMIC_STORE_PTR_RELEASE(*lo, *hi); + FT_ATOMIC_STORE_PTR_RELEASE(*hi, t); ++lo; --hi; } @@ -3845,7 +3845,7 @@ list_ass_subscript_lock_held(PyObject *_self, PyObject *item, PyObject *value) cur += (size_t)step, i++) { garbage[i] = selfitems[cur]; ins = Py_NewRef(seqitems[i]); - selfitems[cur] = ins; + FT_ATOMIC_STORE_PTR_RELEASE(selfitems[cur], ins); } for (i = 0; i < slicelength; i++) {