https://github.com/python/cpython/commit/7b9d406729e7e7adc482b5b8c920de1874c234d0
commit: 7b9d406729e7e7adc482b5b8c920de1874c234d0
branch: main
author: Donghee Na <[email protected]>
committer: corona10 <[email protected]>
date: 2024-02-01T08:58:08+09:00
summary:

gh-112087: Make PyList_{Append,Size,GetSlice} to be thread-safe (gh-114651)

files:
M Include/internal/pycore_list.h
M Include/object.h
M Objects/listobject.c

diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h
index 6c29d882335512..4536f90e414493 100644
--- a/Include/internal/pycore_list.h
+++ b/Include/internal/pycore_list.h
@@ -24,12 +24,13 @@ extern void _PyList_Fini(_PyFreeListState *);
 extern int
 _PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem);
 
+// In free-threaded build: self should be locked by the caller, if it should 
be thread-safe.
 static inline int
 _PyList_AppendTakeRef(PyListObject *self, PyObject *newitem)
 {
     assert(self != NULL && newitem != NULL);
     assert(PyList_Check(self));
-    Py_ssize_t len = PyList_GET_SIZE(self);
+    Py_ssize_t len = Py_SIZE(self);
     Py_ssize_t allocated = self->allocated;
     assert((size_t)len + 1 < PY_SSIZE_T_MAX);
     if (allocated > len) {
diff --git a/Include/object.h b/Include/object.h
index ef3fb721c2b012..568d315d7606c4 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -428,7 +428,11 @@ static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject 
*type) {
 static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) {
     assert(ob->ob_base.ob_type != &PyLong_Type);
     assert(ob->ob_base.ob_type != &PyBool_Type);
+#ifdef Py_GIL_DISABLED
+    _Py_atomic_store_ssize_relaxed(&ob->ob_size, size);
+#else
     ob->ob_size = size;
+#endif
 }
 #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
 #  define Py_SET_SIZE(ob, size) Py_SET_SIZE(_PyVarObject_CAST(ob), (size))
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 56785e5f37a450..80a1f1da55b8bc 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -30,7 +30,6 @@ get_list_state(void)
 }
 #endif
 
-
 /* Ensure ob_item has room for at least newsize elements, and set
  * ob_size to newsize.  If newsize > ob_size on entry, the content
  * of the new slots at exit is undefined heap trash; it's the caller's
@@ -221,8 +220,9 @@ PyList_Size(PyObject *op)
         PyErr_BadInternalCall();
         return -1;
     }
-    else
-        return Py_SIZE(op);
+    else {
+        return PyList_GET_SIZE(op);
+    }
 }
 
 static inline int
@@ -328,7 +328,7 @@ PyList_Insert(PyObject *op, Py_ssize_t where, PyObject 
*newitem)
 int
 _PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem)
 {
-    Py_ssize_t len = PyList_GET_SIZE(self);
+    Py_ssize_t len = Py_SIZE(self);
     assert(self->allocated == -1 || self->allocated == len);
     if (list_resize(self, len + 1) < 0) {
         Py_DECREF(newitem);
@@ -342,7 +342,11 @@ int
 PyList_Append(PyObject *op, PyObject *newitem)
 {
     if (PyList_Check(op) && (newitem != NULL)) {
-        return _PyList_AppendTakeRef((PyListObject *)op, Py_NewRef(newitem));
+        int ret;
+        Py_BEGIN_CRITICAL_SECTION(op);
+        ret = _PyList_AppendTakeRef((PyListObject *)op, Py_NewRef(newitem));
+        Py_END_CRITICAL_SECTION();
+        return ret;
     }
     PyErr_BadInternalCall();
     return -1;
@@ -473,7 +477,7 @@ static PyObject *
 list_item(PyObject *aa, Py_ssize_t i)
 {
     PyListObject *a = (PyListObject *)aa;
-    if (!valid_index(i, Py_SIZE(a))) {
+    if (!valid_index(i, PyList_GET_SIZE(a))) {
         PyErr_SetObject(PyExc_IndexError, &_Py_STR(list_err));
         return NULL;
     }
@@ -511,6 +515,8 @@ PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t 
ihigh)
         PyErr_BadInternalCall();
         return NULL;
     }
+    PyObject *ret;
+    Py_BEGIN_CRITICAL_SECTION(a);
     if (ilow < 0) {
         ilow = 0;
     }
@@ -523,7 +529,9 @@ PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t 
ihigh)
     else if (ihigh > Py_SIZE(a)) {
         ihigh = Py_SIZE(a);
     }
-    return list_slice((PyListObject *)a, ilow, ihigh);
+    ret = list_slice((PyListObject *)a, ilow, ihigh);
+    Py_END_CRITICAL_SECTION();
+    return ret;
 }
 
 static PyObject *

_______________________________________________
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