Skip to content

Commit e546876

Browse files
[3.13] gh-127521: Mark list as "shared" before resizing if necessary (GH-127524) (GH-127533)
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 c7dec02) Co-authored-by: Sam Gross <[email protected]>
1 parent a853610 commit e546876

File tree

1 file changed

+20
-0
lines changed

1 file changed

+20
-0
lines changed

Objects/listobject.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ free_list_items(PyObject** items, bool use_qsbr)
7777
#endif
7878
}
7979

80+
static void
81+
ensure_shared_on_resize(PyListObject *self)
82+
{
83+
#ifdef Py_GIL_DISABLED
84+
// Ensure that the list array is freed using QSBR if we are not the
85+
// owning thread.
86+
if (!_Py_IsOwnedByCurrentThread((PyObject *)self) &&
87+
!_PyObject_GC_IS_SHARED(self))
88+
{
89+
_PyObject_GC_SET_SHARED(self);
90+
}
91+
#endif
92+
}
93+
8094
/* Ensure ob_item has room for at least newsize elements, and set
8195
* ob_size to newsize. If newsize > ob_size on entry, the content
8296
* 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)
126140
if (newsize == 0)
127141
new_allocated = 0;
128142

143+
ensure_shared_on_resize(self);
144+
129145
#ifdef Py_GIL_DISABLED
130146
_PyListArray *array = list_allocate_array(new_allocated);
131147
if (array == NULL) {
@@ -842,6 +858,9 @@ list_clear_impl(PyListObject *a, bool is_resize)
842858
Py_XDECREF(items[i]);
843859
}
844860
#ifdef Py_GIL_DISABLED
861+
if (is_resize) {
862+
ensure_shared_on_resize(a);
863+
}
845864
bool use_qsbr = is_resize && _PyObject_GC_IS_SHARED(a);
846865
#else
847866
bool use_qsbr = false;
@@ -3107,6 +3126,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
31073126
Py_XDECREF(final_ob_item[i]);
31083127
}
31093128
#ifdef Py_GIL_DISABLED
3129+
ensure_shared_on_resize(self);
31103130
bool use_qsbr = _PyObject_GC_IS_SHARED(self);
31113131
#else
31123132
bool use_qsbr = false;

0 commit comments

Comments
 (0)