Index: Objects/dictobject.c =================================================================== --- Objects/dictobject.c (revision 88933) +++ Objects/dictobject.c (working copy) @@ -9,6 +9,8 @@ #include "Python.h" +/* Maximum number of allowed hash collisions. */ +#define Py_MAX_DICT_COLLISIONS 1000 /* Set a key error with the specified argument, wrapping it in a * tuple automatically so that tuple keys are not unpacked as the @@ -327,6 +329,7 @@ register PyDictEntry *ep; register int cmp; PyObject *startkey; + size_t collisions; i = (size_t)hash & mask; ep = &ep0[i]; @@ -361,6 +364,7 @@ /* In the loop, me_key == dummy is by far (factor of 100s) the least likely outcome, so test for that last. */ + collisions = 1; for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { i = (i << 2) + i + perturb + 1; ep = &ep0[i & mask]; @@ -387,6 +391,11 @@ */ return lookdict(mp, key, hash); } + if (++collisions > Py_MAX_DICT_COLLISIONS) { + PyErr_SetString(PyExc_KeyError, + "too many hash collisions"); + return NULL; + } } else if (ep->me_key == dummy && freeslot == NULL) freeslot = ep; @@ -413,6 +422,7 @@ register size_t mask = (size_t)mp->ma_mask; PyDictEntry *ep0 = mp->ma_table; register PyDictEntry *ep; + size_t collisions; /* Make sure this function doesn't have to handle non-string keys, including subclasses of str; e.g., one reason to subclass @@ -439,17 +449,24 @@ /* In the loop, me_key == dummy is by far (factor of 100s) the least likely outcome, so test for that last. */ + collisions = 1; for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { i = (i << 2) + i + perturb + 1; ep = &ep0[i & mask]; if (ep->me_key == NULL) return freeslot == NULL ? ep : freeslot; - if (ep->me_key == key - || (ep->me_hash == hash - && ep->me_key != dummy - && _PyString_Eq(ep->me_key, key))) + if (ep->me_key == key) return ep; - if (ep->me_key == dummy && freeslot == NULL) + if (ep->me_hash == hash && ep->me_key != dummy) { + if (_PyString_Eq(ep->me_key, key)) + return ep; + if (++collisions > Py_MAX_DICT_COLLISIONS) { + PyErr_SetString(PyExc_KeyError, + "too many hash collisions"); + return NULL; + } + } + else if (ep->me_key == dummy && freeslot == NULL) freeslot = ep; } assert(0); /* NOT REACHED */