diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index c0df9507bd7f5e..6e7718253e4def 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -675,6 +675,35 @@ 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) + # cover the case in gh-141805 that triggers segfault + repr(tasks) + 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..37ec77437bbefe --- /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 corruption due to invalid length calculation when set additions occur +in the element comparison (:meth:`object.__eq__`) methods. diff --git a/Objects/setobject.c b/Objects/setobject.c index 5f868c858273ee..b88e5696965575 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -298,6 +298,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--);