Skip to content

Commit a734fd5

Browse files
authored
gh-112069: Make setiter_iternext to be thread-safe (gh-117935)
1 parent 3284b84 commit a734fd5

File tree

1 file changed

+17
-12
lines changed

1 file changed

+17
-12
lines changed

Objects/setobject.c

+17-12
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,30 +843,35 @@ 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)
861-
goto fail;
868+
if (key == NULL) {
869+
si->si_set = NULL;
870+
Py_DECREF(so);
871+
return NULL;
872+
}
862873
si->len--;
863-
key = entry[i].key;
864-
return Py_NewRef(key);
865-
866-
fail:
867-
si->si_set = NULL;
868-
Py_DECREF(so);
869-
return NULL;
874+
return key;
870875
}
871876

872877
PyTypeObject PySetIter_Type = {

0 commit comments

Comments
 (0)