diff -r 1d7496eff907 Lib/test/test_dict.py --- a/Lib/test/test_dict.py Fri Jul 03 23:55:23 2015 -0700 +++ b/Lib/test/test_dict.py Sat Jul 04 15:30:31 2015 +0100 @@ -208,6 +208,26 @@ self.assertRaises(Exc, {}.update, badseq()) self.assertRaises(ValueError, {}.update, [(1, 2, 3)]) + + #Issue 24407 + class ClearingEq: + def __init__(self, to_clear): + self.to_clear = to_clear + + def __hash__(self): + return 0 + + def __eq__(self, o): + self.to_clear.clear() + return False + + l = [(i,0) for i in range(1, 1337)] + other = dict(l) + other[ClearingEq(other)] = 0 + d = {ClearingEq(other): 0, 1: 1} + #Should raise Runtime error, previously this segfaulted. + self.assertRaises(RuntimeError, d.update, other) + def test_fromkeys(self): self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) diff -r 1d7496eff907 Objects/dictobject.c --- a/Objects/dictobject.c Fri Jul 03 23:55:23 2015 -0700 +++ b/Objects/dictobject.c Sat Jul 04 15:30:31 2015 +0100 @@ -2021,6 +2021,7 @@ } mp = (PyDictObject*)a; if (PyDict_Check(b)) { + int used; other = (PyDictObject*)b; if (other == mp || other->ma_used == 0) /* a.update(a) or a.update({}); nothing to do */ @@ -2037,22 +2038,40 @@ */ if (mp->ma_keys->dk_usable * 3 < other->ma_used * 2) if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) - return -1; + return -1; + used = other->ma_used; for (i = 0, n = DK_SIZE(other->ma_keys); i < n; i++) { PyObject *value; + if (used != other->ma_used) { + PyErr_SetString(PyExc_RuntimeError, + "dictionary changed size during update"); + return -1; + } entry = &other->ma_keys->dk_entries[i]; if (other->ma_values) value = other->ma_values[i]; else value = entry->me_value; - if (value != NULL && - (override || - PyDict_GetItem(a, entry->me_key) == NULL)) { - if (insertdict(mp, entry->me_key, - entry->me_hash, - value) != 0) - return -1; + if (value != NULL) { + /* Turn references to key and value into real references, + * in case 'other' is modified. */ + PyObject *key = entry->me_key; + Py_INCREF(key); + + if (override || PyDict_GetItem(a, key) == NULL) { + int err; + Py_INCREF(value); + err = insertdict(mp, entry->me_key, + entry->me_hash, + value); + Py_DECREF(value); + if (err != 0) { + Py_DECREF(key); + return -1; + } + } + Py_DECREF(key); } } }