gh-112069: Make setiter_iternext to be thread-safe (gh-117935) · python/cpython@a734fd5
@@ -834,7 +834,7 @@ static PyMethodDef setiter_methods[] = {
834834835835static PyObject *setiter_iternext(setiterobject *si)
836836{
837-PyObject *key;
837+PyObject *key = NULL;
838838Py_ssize_t i, mask;
839839setentry *entry;
840840PySetObject *so = si->si_set;
@@ -843,30 +843,35 @@ static PyObject *setiter_iternext(setiterobject *si)
843843return NULL;
844844assert (PyAnySet_Check(so));
845845846-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) {
847849PyErr_SetString(PyExc_RuntimeError,
848850"Set changed size during iteration");
849851si->si_used = -1; /* Make this state sticky */
850852return NULL;
851853 }
852854855+Py_BEGIN_CRITICAL_SECTION(so);
853856i = si->si_pos;
854857assert(i>=0);
855858entry = so->table;
856859mask = 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)) {
858861i++;
862+ }
863+if (i <= mask) {
864+key = Py_NewRef(entry[i].key);
865+ }
866+Py_END_CRITICAL_SECTION();
859867si->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+ }
862873si->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}
871876872877PyTypeObject PySetIter_Type = {