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

def test_clear_at_lookup(self):
d = {}

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

for _ in range(10):
d[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 ``dict`` if ``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 @@ -1899,6 +1899,14 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
if (ix == DKIX_ERROR)
goto Fail;

// 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)
goto Fail;
assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
}

if (ix == DKIX_EMPTY) {
assert(!_PyDict_HasSplitTable(mp));
/* Insert into new slot. */
Expand Down
Loading