gh-141805: Fix crash after concurrent addition objects with the same hash to set (GH-143815)

This happens when the set contained several elements with the same hash,
and then some of them were removed.
This commit is contained in:
Serhiy Storchaka 2026-01-14 23:29:17 +02:00 committed by GitHub
parent f4de184980
commit b8e925b4f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 34 additions and 0 deletions

View File

@ -1853,6 +1853,7 @@ class TestWeirdBugs(unittest.TestCase):
list(si)
def test_merge_and_mutate(self):
# gh-141805
class X:
def __hash__(self):
return hash(0)
@ -1865,6 +1866,33 @@ class TestWeirdBugs(unittest.TestCase):
s = {0}
s.update(other)
def test_hash_collision_concurrent_add(self):
class X:
def __hash__(self):
return 0
class Y:
flag = False
def __hash__(self):
return 0
def __eq__(self, other):
if not self.flag:
self.flag = True
s.add(X())
return self is other
a = X()
s = set()
s.add(a)
s.add(X())
s.remove(a)
# Now the set contains a dummy entry followed by an entry
# for an object with hash 0.
s.add(Y())
# The following operations should not crash.
repr(s)
list(s)
set() | s
class TestOperationsMutating:
"""Regression test for bpo-46615"""

View File

@ -0,0 +1,3 @@
Fix crash in :class:`set` when objects with the same hash are concurrently
added to the set after removing an element with the same hash while the set
still contains elements with the same hash.

View File

@ -308,6 +308,9 @@ set_add_entry_takeref(PySetObject *so, PyObject *key, Py_hash_t hash)
found_unused_or_dummy:
if (freeslot == NULL)
goto found_unused;
if (freeslot->hash != -1) {
goto restart;
}
FT_ATOMIC_STORE_SSIZE_RELAXED(so->used, so->used + 1);
FT_ATOMIC_STORE_SSIZE_RELAXED(freeslot->hash, hash);
FT_ATOMIC_STORE_PTR_RELEASE(freeslot->key, key);