Co-authored-by: Kumar Aditya <kumaraditya@python.org>
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()
--- /dev/null
+In free-threaded build, fix race condition when calling :meth:`!__sizeof__` on a :class:`list`
/*[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);
}