Skip to content
Merged
20 changes: 20 additions & 0 deletions Lib/test/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -1601,6 +1601,26 @@ def __hash__(self):
with self.assertRaises(KeyError):
d.get(key2)

def test_clear_at_lookup(self):
class X(object):
def __hash__(self):
return 1
def __eq__(self, other):
nonlocal d
d.clear()

d = {}
for _ in range(10):
d[X()] = None

self.assertEqual(len(d), 1)

d = {}
for _ in range(10):
d.setdefault(X(), None)

self.assertEqual(len(d), 1)


class CAPITest(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed crash in :class:`dict` if :meth:`dict.clear` is called at the lookup
stage. Patch by Mikhail Efimov.
8 changes: 8 additions & 0 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,14 @@ static inline int
insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
Py_hash_t hash, PyObject *key, PyObject *value)
{
// gh-140551: If dict was cleaned in _Py_dict_lookup,
// we have to resize one more time to force general key kind.
if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) {
if (insertion_resize(mp, 0) < 0)
return -1;
assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
}

if (mp->ma_keys->dk_usable <= 0) {
/* Need to resize. */
if (insertion_resize(mp, 1) < 0) {
Expand Down
Loading