Skip to content

gh-112087: Make list_{subscript, ass_slice, slice} to be thread-safe #115854

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 82 additions & 49 deletions Objects/listobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -506,29 +506,32 @@ list_item(PyObject *aa, Py_ssize_t i)
}

static PyObject *
list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
list_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t len)
{
PyListObject *np;
PyObject **src, **dest;
Py_ssize_t i, len;
len = ihigh - ilow;
if (len <= 0) {
return PyList_New(0);
}
np = (PyListObject *) list_new_prealloc(len);
if (np == NULL)
PyListObject *np = (PyListObject *) list_new_prealloc(len);
if (np == NULL) {
return NULL;

src = a->ob_item + ilow;
dest = np->ob_item;
for (i = 0; i < len; i++) {
}
PyObject **src = a->ob_item + ilow;
PyObject **dest = np->ob_item;
for (Py_ssize_t i = 0; i < len; i++) {
PyObject *v = src[i];
dest[i] = Py_NewRef(v);
FT_ATOMIC_STORE_PTR_RELAXED(dest[i], Py_NewRef(v));
}
Py_SET_SIZE(np, len);
return (PyObject *)np;
}

static PyObject *
list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
{
Py_ssize_t len = ihigh - ilow;
if (len <= 0) {
return PyList_New(0);
}
return list_slice_lock_held(a, ilow, len);
}

PyObject *
PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
{
Expand Down Expand Up @@ -695,7 +698,7 @@ list_clear_slot(PyObject *self)
* guaranteed the call cannot fail.
*/
static int
list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
list_ass_slice_impl(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
{
/* Because [X]DECREF can recursively invoke list operations on
this list, we must postpone all [X]DECREF activity until
Expand All @@ -720,10 +723,10 @@ list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
else {
if (a == b) {
/* Special case "a[i:j] = a" -- copy b first */
v = list_slice(b, 0, Py_SIZE(b));
v = list_slice_lock_held(b, 0, Py_SIZE(b));
if (v == NULL)
return result;
result = list_ass_slice(a, ilow, ihigh, v);
result = list_ass_slice_impl(a, ilow, ihigh, v);
Py_DECREF(v);
return result;
}
Expand Down Expand Up @@ -800,6 +803,23 @@ list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
#undef b
}

static int
list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
{
int ret;
if (v != NULL && PyList_CheckExact(v)) {
Py_BEGIN_CRITICAL_SECTION2(a, v);
ret = list_ass_slice_impl(a, ilow, ihigh, v);
Py_END_CRITICAL_SECTION2();
}
else {
Py_BEGIN_CRITICAL_SECTION(a);
ret = list_ass_slice_impl(a, ilow, ihigh, v);
Py_END_CRITICAL_SECTION();
}
return ret;
}

int
PyList_SetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
{
Expand Down Expand Up @@ -2861,8 +2881,7 @@ list_remove_impl(PyListObject *self, PyObject *value)
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
Py_DECREF(obj);
if (cmp > 0) {
if (list_ass_slice(self, i, i+1,
(PyObject *)NULL) == 0)
if (list_ass_slice_impl(self, i, i+1, NULL) == 0)
Py_RETURN_NONE;
return NULL;
}
Expand Down Expand Up @@ -3062,6 +3081,47 @@ static PySequenceMethods list_as_sequence = {
list_inplace_repeat, /* sq_inplace_repeat */
};

static PyObject *
list_slice_step_lock_held(PyListObject *a, Py_ssize_t start, Py_ssize_t step, Py_ssize_t len)
{
PyObject *obj = list_new_prealloc(len);
if (obj == NULL) {
return NULL;
}
PyListObject *np = (PyListObject *)obj;
size_t cur;
Py_ssize_t i;
PyObject **src = a->ob_item;
PyObject **dest = np->ob_item;
for (cur = start, i = 0; i < len;
cur += (size_t)step, i++) {
PyObject *v = src[cur];
FT_ATOMIC_STORE_PTR_RELAXED(dest[i], Py_NewRef(v));
}
Py_SET_SIZE(np, len);
return (PyObject *)np;
}

static PyObject *
list_slice_wrap(PyListObject *aa, Py_ssize_t start, Py_ssize_t stop, Py_ssize_t step)
{
PyObject *res = NULL;
PyListObject *a = (PyListObject *)aa;
Py_BEGIN_CRITICAL_SECTION(a);
Py_ssize_t len = PySlice_AdjustIndices(Py_SIZE(a), &start, &stop, step);
if (len <= 0) {
res = PyList_New(0);
}
else if (step == 1) {
res = list_slice_lock_held(a, start, len);
}
else {
res = list_slice_step_lock_held(a, start, step, len);
}
Py_END_CRITICAL_SECTION();
return res;
}

static PyObject *
list_subscript(PyObject* _self, PyObject* item)
{
Expand All @@ -3076,38 +3136,11 @@ list_subscript(PyObject* _self, PyObject* item)
return list_item((PyObject *)self, i);
}
else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength, i;
size_t cur;
PyObject* result;
PyObject* it;
PyObject **src, **dest;

Py_ssize_t start, stop, step;
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
return NULL;
}
slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop,
step);

if (slicelength <= 0) {
return PyList_New(0);
}
else if (step == 1) {
return list_slice(self, start, stop);
}
else {
result = list_new_prealloc(slicelength);
if (!result) return NULL;

src = self->ob_item;
dest = ((PyListObject *)result)->ob_item;
for (cur = start, i = 0; i < slicelength;
cur += (size_t)step, i++) {
it = Py_NewRef(src[cur]);
dest[i] = it;
}
Py_SET_SIZE(result, slicelength);
return result;
}
return list_slice_wrap(self, start, stop, step);
}
else {
PyErr_Format(PyExc_TypeError,
Expand Down