Skip to content

Commit c7dec02

Browse files
authored
gh-127521: Mark list as "shared" before resizing if necessary (#127524)
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.
1 parent c430376 commit c7dec02

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
@@ -68,6 +68,20 @@ free_list_items(PyObject** items, bool use_qsbr)
6868
#endif
6969
}
7070

71+
static void
72+
ensure_shared_on_resize(PyListObject *self)
73+
{
74+
#ifdef Py_GIL_DISABLED
75+
// Ensure that the list array is freed using QSBR if we are not the
76+
// owning thread.
77+
if (!_Py_IsOwnedByCurrentThread((PyObject *)self) &&
78+
!_PyObject_GC_IS_SHARED(self))
79+
{
80+
_PyObject_GC_SET_SHARED(self);
81+
}
82+
#endif
83+
}
84+
7185
/* Ensure ob_item has room for at least newsize elements, and set
7286
* ob_size to newsize. If newsize > ob_size on entry, the content
7387
* of the new slots at exit is undefined heap trash; it's the caller's
@@ -117,6 +131,8 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
117131
if (newsize == 0)
118132
new_allocated = 0;
119133

134+
ensure_shared_on_resize(self);
135+
120136
#ifdef Py_GIL_DISABLED
121137
_PyListArray *array = list_allocate_array(new_allocated);
122138
if (array == NULL) {
@@ -804,6 +820,9 @@ list_clear_impl(PyListObject *a, bool is_resize)
804820
Py_XDECREF(items[i]);
805821
}
806822
#ifdef Py_GIL_DISABLED
823+
if (is_resize) {
824+
ensure_shared_on_resize(a);
825+
}
807826
bool use_qsbr = is_resize && _PyObject_GC_IS_SHARED(a);
808827
#else
809828
bool use_qsbr = false;
@@ -3069,6 +3088,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
30693088
Py_XDECREF(final_ob_item[i]);
30703089
}
30713090
#ifdef Py_GIL_DISABLED
3091+
ensure_shared_on_resize(self);
30723092
bool use_qsbr = _PyObject_GC_IS_SHARED(self);
30733093
#else
30743094
bool use_qsbr = false;

0 commit comments

Comments
 (0)