summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorFred Drake <fdrake@acm.org>2000-08-31 19:04:07 (GMT)
committerFred Drake <fdrake@acm.org>2000-08-31 19:04:07 (GMT)
commitc88b99ce060e37a9098708483b7e3c8b5db87fbd (patch)
tree96f8e7021566516eab50215c4f549a5bb7d7f091 /Objects
parenta3895c0d291c795ed9e36fd86118d6679f1d917b (diff)
downloadcpython-c88b99ce060e37a9098708483b7e3c8b5db87fbd.zip
cpython-c88b99ce060e37a9098708483b7e3c8b5db87fbd.tar.gz
cpython-c88b99ce060e37a9098708483b7e3c8b5db87fbd.tar.bz2
Clear errors raised by PyObject_Compare() without losing any existing
exception context. This avoids improperly propogating errors raised by a user-defined __cmp__() by a subsequent lookup operation. This patch does *not* include the performance enhancement patch for dictionaries with string keys only; that will be checked in separately. This closes SourceForge patch #101277 and bug #112558.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/dictobject.c53
1 files changed, 44 insertions, 9 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index ddd8eb8..621ed73 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -139,6 +139,10 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
register unsigned int mask = mp->ma_size-1;
dictentry *ep0 = mp->ma_table;
register dictentry *ep;
+ register int restore_error = 0;
+ register int checked_error = 0;
+ register int cmp;
+ PyObject *err_type, *err_value, *err_tb;
/* We must come up with (i, incr) such that 0 <= i < ma_size
and 0 < incr < ma_size and both are a function of hash */
i = (~hash) & mask;
@@ -151,14 +155,25 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
if (ep->me_key == dummy)
freeslot = ep;
else {
- if (ep->me_hash == hash &&
- PyObject_Compare(ep->me_key, key) == 0)
- {
- return ep;
+ if (ep->me_hash == hash) {
+ /* error can't have been checked yet */
+ checked_error = 1;
+ if (PyErr_Occurred()) {
+ restore_error = 1;
+ PyErr_Fetch(&err_type, &err_value, &err_tb);
+ }
+ cmp = PyObject_Compare(ep->me_key, key);
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ else if (cmp == 0) {
+ if (restore_error)
+ PyErr_Restore(err_type, err_value,
+ err_tb);
+ return ep;
+ }
}
freeslot = NULL;
}
- /* XXX What if PyObject_Compare returned an exception? */
/* Derive incr from hash, just to make it more arbitrary. Note that
incr must not be 0, or we will get into an infinite loop.*/
incr = (hash ^ ((unsigned long)hash >> 3)) & mask;
@@ -167,6 +182,8 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
for (;;) {
ep = &ep0[(i+incr)&mask];
if (ep->me_key == NULL) {
+ if (restore_error)
+ PyErr_Restore(err_type, err_value, err_tb);
if (freeslot != NULL)
return freeslot;
else
@@ -176,12 +193,30 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
if (freeslot == NULL)
freeslot = ep;
}
- else if (ep->me_key == key ||
- (ep->me_hash == hash &&
- PyObject_Compare(ep->me_key, key) == 0)) {
+ else if (ep->me_key == key) {
+ if (restore_error)
+ PyErr_Restore(err_type, err_value, err_tb);
return ep;
+ }
+ else if (ep->me_hash == hash) {
+ if (!checked_error) {
+ checked_error = 1;
+ if (PyErr_Occurred()) {
+ restore_error = 1;
+ PyErr_Fetch(&err_type, &err_value,
+ &err_tb);
+ }
+ }
+ cmp = PyObject_Compare(ep->me_key, key);
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ else if (cmp == 0) {
+ if (restore_error)
+ PyErr_Restore(err_type, err_value,
+ err_tb);
+ return ep;
+ }
}
- /* XXX What if PyObject_Compare returned an exception? */
/* Cycle through GF(2^n)-{0} */
incr = incr << 1;
if (incr > mask)