diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index c0df9507bd7f5e..951225ddc24f2b 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -675,6 +675,33 @@ def __hash__(self): with self.assertRaises(KeyError): myset.discard(elem2) + def test_set_add_to_dummy_slot(self): + # gh-141805 + tasks = set() + + class Dummy: + def __hash__(self): + return 0 + + class CorruptTrigger: + triggered = False + + def __hash__(self): + return 0 + + def __eq__(self, value): + if not self.triggered: + self.triggered = True + tasks.add(self) + return False + + tasks.add(Dummy()) + tasks.add(Dummy()) + tasks.pop() + self.assertEqual(len(tasks), 1) + tasks.add(CorruptTrigger()) + self.assertEqual(len(tasks), 2) + class SetSubclass(set): pass diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-11-27-17-47-09.gh-issue-141805.TT0biF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-27-17-47-09.gh-issue-141805.TT0biF.rst new file mode 100644 index 00000000000000..9b4f32508f1dd2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-27-17-47-09.gh-issue-141805.TT0biF.rst @@ -0,0 +1,2 @@ +Fix set length corruption when set additions occur within +element comparison (:meth:`object.__eq__`) methods. diff --git a/Objects/setobject.c b/Objects/setobject.c index 85f4d7d403178a..3a8a5e3e7ecd56 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -180,6 +180,7 @@ set_add_entry_takeref(PySetObject *so, PyObject *key, Py_hash_t hash) else if (entry->hash == -1) { assert (entry->key == dummy); freeslot = entry; + goto found_unused_or_dummy; } entry++; } while (probes--);