https://github.com/python/cpython/commit/2af2a3830258e9bbed6429fa45c0594ebfc866f8
commit: 2af2a3830258e9bbed6429fa45c0594ebfc866f8
branch: 3.14
author: bkap123 <[email protected]>
committer: colesbury <[email protected]>
date: 2026-03-12T22:06:12-04:00
summary:

[3.14] gh-145036: Fix data race for list capacity in free-threading (GH-145365) 
(#145881)

(cherry picked from commit 9e0802330caca51fed7fc0c8c1dcce2daf03d8bd)

Co-authored-by: Kumar Aditya <[email protected]>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2026-02-28-18-42-36.gh-issue-145036.70Kbfz.rst
M Lib/test/test_free_threading/test_list.py
M Objects/listobject.c

diff --git a/Lib/test/test_free_threading/test_list.py 
b/Lib/test/test_free_threading/test_list.py
index 44c0ac74e02aa3..4e68dde494118e 100644
--- a/Lib/test/test_free_threading/test_list.py
+++ b/Lib/test/test_free_threading/test_list.py
@@ -91,6 +91,27 @@ def copy_back_and_forth(b, l):
         with threading_helper.start_threads(threads):
             pass
 
+    # gh-145036: race condition with list.__sizeof__()
+    def test_list_sizeof_free_threaded_build(self):
+        L = []
+
+        def mutate_function():
+            for _ in range(100):
+                L.append(1)
+                L.pop()
+
+        def size_function():
+            for _ in range(100):
+                L.__sizeof__()
+
+        threads = []
+        for _ in range(4):
+            threads.append(Thread(target=mutate_function))
+            threads.append(Thread(target=size_function))
+
+        with threading_helper.start_threads(threads):
+            pass
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-28-18-42-36.gh-issue-145036.70Kbfz.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-28-18-42-36.gh-issue-145036.70Kbfz.rst
new file mode 100644
index 00000000000000..2a565c1d02bc2e
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-28-18-42-36.gh-issue-145036.70Kbfz.rst
@@ -0,0 +1 @@
+In free-threaded build, fix race condition when calling :meth:`!__sizeof__` on 
a :class:`list`
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 23d3472b6d4153..98c90665be5721 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -3538,8 +3538,14 @@ list___sizeof___impl(PyListObject *self)
 /*[clinic end generated code: output=3417541f95f9a53e input=b8030a5d5ce8a187]*/
 {
     size_t res = _PyObject_SIZE(Py_TYPE(self));
-    Py_ssize_t allocated = FT_ATOMIC_LOAD_SSIZE_RELAXED(self->allocated);
-    res += (size_t)allocated * sizeof(void*);
+#ifdef Py_GIL_DISABLED
+    PyObject **ob_item = _Py_atomic_load_ptr(&self->ob_item);
+    if (ob_item != NULL) {
+        res += list_capacity(ob_item) * sizeof(PyObject *);
+    }
+#else
+    res += (size_t)self->allocated * sizeof(PyObject *);
+#endif
     return PyLong_FromSize_t(res);
 }
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to