Skip to content

Commit ab18f4e

Browse files
committed
pythongh-112069: Make setiter_iternext to be thread-safe
1 parent acf69e0 commit ab18f4e

1 file changed

Lines changed: 15 additions & 6 deletions

File tree

‎Objects/setobject.c‎

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ static PyMethodDef setiter_methods[] = {
834834

835835
static PyObject *setiter_iternext(setiterobject *si)
836836
{
837-
PyObject *key;
837+
PyObject *key = NULL;
838838
Py_ssize_t i, mask;
839839
setentry *entry;
840840
PySetObject *so = si->si_set;
@@ -843,29 +843,38 @@ static PyObject *setiter_iternext(setiterobject *si)
843843
return NULL;
844844
assert (PyAnySet_Check(so));
845845

846-
if (si->si_used != so->used) {
846+
Py_ssize_t so_used = FT_ATOMIC_LOAD_SSIZE(so->used);
847+
Py_ssize_t si_used = FT_ATOMIC_LOAD_SSIZE(si->si_used);
848+
if (si_used != so_used) {
847849
PyErr_SetString(PyExc_RuntimeError,
848850
"Set changed size during iteration");
849851
si->si_used = -1; /* Make this state sticky */
850852
return NULL;
851853
}
852854

855+
Py_BEGIN_CRITICAL_SECTION(so);
853856
i = si->si_pos;
854857
assert(i>=0);
855858
entry = so->table;
856859
mask = so->mask;
857-
while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy))
860+
while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) {
858861
i++;
862+
}
863+
if (i <= mask) {
864+
key = Py_NewRef(entry[i].key);
865+
}
866+
Py_END_CRITICAL_SECTION();
859867
si->si_pos = i+1;
860-
if (i > mask)
868+
if (key == NULL) {
861869
goto fail;
870+
}
862871
si->len--;
863-
key = entry[i].key;
864-
return Py_NewRef(key);
872+
return key;
865873

866874
fail:
867875
si->si_set = NULL;
868876
Py_DECREF(so);
877+
Py_XDECREF(key);
869878
return NULL;
870879
}
871880

0 commit comments

Comments
 (0)