lookdict:  stop more insane core-dump mutating comparison cases.  Should
be possible to provoke unbounded recursion now, but leaving that to someone
else to provoke and repair.
Bugfix candidate -- although this is getting harder to backstitch, and the
cases it's protecting against are mondo contrived.
diff --git a/Lib/test/test_mutants.py b/Lib/test/test_mutants.py
index 88a3a02..9ee1bb7 100644
--- a/Lib/test/test_mutants.py
+++ b/Lib/test/test_mutants.py
@@ -215,3 +215,71 @@
 f.close()
 os.unlink(TESTFN)
 del f, dict
+
+
+##########################################################################
+# And another core-dumper from Michael Hudson.
+
+dict = {}
+
+# let's force dict to malloc its table
+for i in range(1, 10):
+    dict[i] = i
+
+class Machiavelli2:
+    def __eq__(self, other):
+        dict.clear()
+        return 1
+
+    def __hash__(self):
+        return 0
+
+dict[Machiavelli2()] = Machiavelli2()
+
+try:
+    dict[Machiavelli2()]
+except KeyError:
+    pass
+
+del dict
+
+##########################################################################
+# And another core-dumper from Michael Hudson.
+
+dict = {}
+
+# let's force dict to malloc its table
+for i in range(1, 10):
+    dict[i] = i
+
+class Machiavelli3:
+    def __init__(self, id):
+        self.id = id
+
+    def __eq__(self, other):
+        if self.id == other.id:
+            dict.clear()
+            return 1
+        else:
+            return 0
+
+    def __repr__(self):
+        return "%s(%s)"%(self.__class__.__name__, self.id)
+
+    def __hash__(self):
+        return 0
+
+dict[Machiavelli3(1)] = Machiavelli3(0)
+dict[Machiavelli3(2)] = Machiavelli3(0)
+
+f = open(TESTFN, "w")
+try:
+    try:
+        print >> f, dict[Machiavelli3(2)]
+    except KeyError:
+        pass
+finally:
+    f.close()
+    os.unlink(TESTFN)
+
+del dict
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 69fe67e..ce44abe 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -255,6 +255,7 @@
 	register int checked_error;
 	register int cmp;
 	PyObject *err_type, *err_value, *err_tb;
+	PyObject *startkey;
 
 	i = hash & mask;
 	ep = &ep0[i];
@@ -272,11 +273,23 @@
 				restore_error = 1;
 				PyErr_Fetch(&err_type, &err_value, &err_tb);
 			}
-			cmp = PyObject_RichCompareBool(ep->me_key, key, Py_EQ);
-			if (cmp > 0)
-				goto Done;
+			startkey = ep->me_key;
+			cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
 			if (cmp < 0)
 				PyErr_Clear();
+			if (ep0 == mp->ma_table && ep->me_key == startkey) {
+				if (cmp > 0)
+					goto Done;
+			}
+			else {
+				/* The compare did major nasty stuff to the
+				 * dict:  start over.
+				 * XXX A clever adversary could prevent this
+				 * XXX from terminating.
+ 				 */
+ 				ep = lookdict(mp, key, hash);
+ 				goto Done;
+ 			}
 		}
 		freeslot = NULL;
 	}
@@ -302,11 +315,23 @@
 						    &err_tb);
 				}
 			}
-			cmp = PyObject_RichCompareBool(ep->me_key, key, Py_EQ);
-			if (cmp > 0)
-				break;
+			startkey = ep->me_key;
+			cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
 			if (cmp < 0)
 				PyErr_Clear();
+			if (ep0 == mp->ma_table && ep->me_key == startkey) {
+				if (cmp > 0)
+					break;
+			}
+			else {
+				/* The compare did major nasty stuff to the
+				 * dict:  start over.
+				 * XXX A clever adversary could prevent this
+				 * XXX from terminating.
+ 				 */
+ 				ep = lookdict(mp, key, hash);
+ 				break;
+ 			}
 		}
 		else if (ep->me_key == dummy && freeslot == NULL)
 			freeslot = ep;