summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-06-03 04:54:32 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-06-03 04:54:32 (GMT)
commit453163d842568dd066cfb5f047f3948d177743d7 (patch)
tree79d56026ba883ec59810d1eb8dfa476d10ddb39a
parent7b5d0afb1ec0e9cc10e74779d0e80bb1bee83577 (diff)
downloadcpython-453163d842568dd066cfb5f047f3948d177743d7.zip
cpython-453163d842568dd066cfb5f047f3948d177743d7.tar.gz
cpython-453163d842568dd066cfb5f047f3948d177743d7.tar.bz2
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.
-rw-r--r--Lib/test/test_mutants.py68
-rw-r--r--Objects/dictobject.c37
2 files changed, 99 insertions, 6 deletions
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 @@ print >> f, str(dict)
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 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
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 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
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 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
&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;