diff -r 93996b0e07f2 Include/dictobject.h --- a/Include/dictobject.h Mon Mar 05 10:50:11 2012 +0100 +++ b/Include/dictobject.h Mon Mar 05 18:11:02 2012 +0100 @@ -84,6 +84,7 @@ struct _dictobject { PyDictEntry *ma_table; PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, Py_hash_t hash); PyDictEntry ma_smalltable[PyDict_MINSIZE]; + int in_lookup; }; #endif /* Py_LIMITED_API */ diff -r 93996b0e07f2 Lib/test/test_sys.py --- a/Lib/test/test_sys.py Mon Mar 05 10:50:11 2012 +0100 +++ b/Lib/test/test_sys.py Mon Mar 05 18:11:02 2012 +0100 @@ -687,9 +687,9 @@ class SizeofTest(unittest.TestCase): # method-wrapper (descriptor object) check({}.__iter__, size(h + '2P')) # dict - check({}, size(h + '3P2P' + 8*'P2P')) + check({}, size(h + '3P2P' + 8*'P2P' + 'I')) longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8} - check(longdict, size(h + '3P2P' + 8*'P2P') + 16*size('P2P')) + check(longdict, size(h + '3P2P' + 8*'P2P' + 'I') + 16*size('P2P')) # dictionary-keyiterator check({}.keys(), size(h + 'P')) # dictionary-valueiterator diff -r 93996b0e07f2 Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py Mon Mar 05 10:50:11 2012 +0100 +++ b/Lib/test/test_weakref.py Mon Mar 05 18:11:02 2012 +0100 @@ -1285,7 +1285,7 @@ class MappingTestCase(TestBase): for o in objs: count += 1 del d[o] - self.assertEqual(len(d), 0) + self.assertEqual(len(d), 2) self.assertEqual(count, 2) from test import mapping_tests diff -r 93996b0e07f2 Objects/dictobject.c --- a/Objects/dictobject.c Mon Mar 05 10:50:11 2012 +0100 +++ b/Objects/dictobject.c Mon Mar 05 18:11:02 2012 +0100 @@ -202,6 +202,7 @@ show_track(void) #define INIT_NONZERO_DICT_SLOTS(mp) do { \ (mp)->ma_table = (mp)->ma_smalltable; \ (mp)->ma_mask = PyDict_MINSIZE - 1; \ + (mp)->in_lookup = 0; \ } while(0) #define EMPTY_TO_MINSIZE(mp) do { \ @@ -338,7 +339,9 @@ lookdict(PyDictObject *mp, PyObject *key if (ep->me_hash == hash) { startkey = ep->me_key; Py_INCREF(startkey); + mp->in_lookup = 1; cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + mp->in_lookup = 0; Py_DECREF(startkey); if (cmp < 0) return NULL; @@ -370,7 +373,9 @@ lookdict(PyDictObject *mp, PyObject *key if (ep->me_hash == hash && ep->me_key != dummy) { startkey = ep->me_key; Py_INCREF(startkey); + mp->in_lookup = 1; cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + mp->in_lookup = 0; Py_DECREF(startkey); if (cmp < 0) return NULL; @@ -803,6 +808,13 @@ dict_set_item_by_hash_or_entry(register mp = (PyDictObject *)op; assert(mp->ma_fill <= mp->ma_mask); /* at least one empty slot */ + + if (mp->in_lookup) { + PyErr_SetString(PyExc_RuntimeError, + "cannot modify a dict during a lookup"); + return -1; + } + n_used = mp->ma_used; Py_INCREF(value); Py_INCREF(key); @@ -883,6 +895,12 @@ PyDict_DelItem(PyObject *op, PyObject *k return -1; } mp = (PyDictObject *)op; + if (mp->in_lookup) { + PyErr_SetString(PyExc_RuntimeError, + "cannot modify a dict during a lookup"); + return -1; + } + ep = (mp->ma_lookup)(mp, key, hash); if (ep == NULL) return -1; @@ -1843,6 +1861,11 @@ dict_setdefault(register PyDictObject *m static PyObject * dict_clear(register PyDictObject *mp) { + if (mp->in_lookup) { + PyErr_SetString(PyExc_RuntimeError, + "cannot modify a dict during a lookup"); + return NULL; + } PyDict_Clear((PyObject *)mp); Py_RETURN_NONE; }