From 3238136ea9ac93730deb9282e3cce1c4d0c6b873 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 6 Mar 2025 17:44:54 +0000 Subject: [PATCH] gh-130920: Fix data race in STORE_SUBSCR_LIST_INT The write of the item to the list needs to use an atomic operation in the free threading build. Co-authored-by: Tomasz Pytel --- Lib/test/test_free_threading/test_list.py | 16 +++++++++++++++- Python/bytecodes.c | 3 ++- Python/executor_cases.c.h | 3 ++- Python/generated_cases.c.h | 3 ++- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_free_threading/test_list.py b/Lib/test/test_free_threading/test_list.py index a705161369e8dd..2c9af65273a1c8 100644 --- a/Lib/test/test_free_threading/test_list.py +++ b/Lib/test/test_free_threading/test_list.py @@ -1,6 +1,6 @@ import unittest -from threading import Thread +from threading import Thread, Barrier from unittest import TestCase from test.support import threading_helper @@ -71,6 +71,20 @@ def reader_func(): for reader in readers: reader.join() + def test_store_list_int(self): + def copy_back_and_forth(b, l): + b.wait() + for _ in range(100): + l[0] = l[1] + l[1] = l[0] + + l = [0, 1] + barrier = Barrier(NTHREAD) + threads = [Thread(target=copy_back_and_forth, args=(barrier, l)) + for _ in range(NTHREAD)] + with threading_helper.start_threads(threads): + pass + if __name__ == "__main__": unittest.main() diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 24aa7bbb87c193..718c8f5607c55b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1015,7 +1015,8 @@ dummy_func( STAT_INC(STORE_SUBSCR, hit); PyObject *old_value = PyList_GET_ITEM(list, index); - PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); + FT_ATOMIC_STORE_PTR_RELEASE(_PyList_ITEMS(list)[index], + PyStackRef_AsPyObjectSteal(value)); assert(old_value != NULL); UNLOCK_OBJECT(list); // unlock before decrefs! PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 29160b9f6634c5..94f05c62089056 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1522,7 +1522,8 @@ } STAT_INC(STORE_SUBSCR, hit); PyObject *old_value = PyList_GET_ITEM(list, index); - PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); + FT_ATOMIC_STORE_PTR_RELEASE(_PyList_ITEMS(list)[index], + PyStackRef_AsPyObjectSteal(value)); assert(old_value != NULL); UNLOCK_OBJECT(list); // unlock before decrefs! PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 5216918560a487..33d00afea18e1c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -11259,7 +11259,8 @@ } STAT_INC(STORE_SUBSCR, hit); PyObject *old_value = PyList_GET_ITEM(list, index); - PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value)); + FT_ATOMIC_STORE_PTR_RELEASE(_PyList_ITEMS(list)[index], + PyStackRef_AsPyObjectSteal(value)); assert(old_value != NULL); UNLOCK_OBJECT(list); // unlock before decrefs! PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc);