]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-127521: Mark list as "shared" before resizing if necessary (GH-127524)...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 3 Dec 2024 00:22:05 +0000 (01:22 +0100)
committerGitHub <noreply@github.com>
Tue, 3 Dec 2024 00:22:05 +0000 (19:22 -0500)
In the free threading build, if a non-owning thread resizes a list,
it must use QSBR to free the old list array because there may be a
concurrent access (without a lock) from the owning thread.

To match the pattern in dictobject.c, we just mark the list as "shared"
before resizing if it's from a non-owning thread and not already marked
as shared.
(cherry picked from commit c7dec02de2ed4baf3cd22ad094350265b52c18af)

Co-authored-by: Sam Gross <colesbury@gmail.com>
Objects/listobject.c

index dc9df3c3614fb4c7c94da16de833a0f051f95d1b..89abbda155a8b614fff5e76695861bfa07cda73a 100644 (file)
@@ -77,6 +77,20 @@ free_list_items(PyObject** items, bool use_qsbr)
 #endif
 }
 
+static void
+ensure_shared_on_resize(PyListObject *self)
+{
+#ifdef Py_GIL_DISABLED
+    // Ensure that the list array is freed using QSBR if we are not the
+    // owning thread.
+    if (!_Py_IsOwnedByCurrentThread((PyObject *)self) &&
+        !_PyObject_GC_IS_SHARED(self))
+    {
+        _PyObject_GC_SET_SHARED(self);
+    }
+#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
@@ -126,6 +140,8 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
     if (newsize == 0)
         new_allocated = 0;
 
+    ensure_shared_on_resize(self);
+
 #ifdef Py_GIL_DISABLED
     _PyListArray *array = list_allocate_array(new_allocated);
     if (array == NULL) {
@@ -842,6 +858,9 @@ list_clear_impl(PyListObject *a, bool is_resize)
         Py_XDECREF(items[i]);
     }
 #ifdef Py_GIL_DISABLED
+    if (is_resize) {
+        ensure_shared_on_resize(a);
+    }
     bool use_qsbr = is_resize && _PyObject_GC_IS_SHARED(a);
 #else
     bool use_qsbr = false;
@@ -3107,6 +3126,7 @@ keyfunc_fail:
             Py_XDECREF(final_ob_item[i]);
         }
 #ifdef Py_GIL_DISABLED
+        ensure_shared_on_resize(self);
         bool use_qsbr = _PyObject_GC_IS_SHARED(self);
 #else
         bool use_qsbr = false;