diff options
author | Tim Peters <tim.peters@gmail.com> | 2001-06-03 04:54:32 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2001-06-03 04:54:32 (GMT) |
commit | 453163d842568dd066cfb5f047f3948d177743d7 (patch) | |
tree | 79d56026ba883ec59810d1eb8dfa476d10ddb39a | |
parent | 7b5d0afb1ec0e9cc10e74779d0e80bb1bee83577 (diff) | |
download | cpython-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.py | 68 | ||||
-rw-r--r-- | Objects/dictobject.c | 37 |
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; |