Mercurial > cpython-lru_cache-weakref
diff Objects/dictobject.c @ 14307:b24db770dffd legacy-trunk
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.
| author | Fred Drake <fdrake@acm.org> |
|---|---|
| date | Thu, 31 Aug 2000 19:04:07 +0000 |
| parents | 2190b7599837 |
| children | 2db807f345bc |
line wrap: on
line diff
--- a/Objects/dictobject.c Thu Aug 31 18:11:07 2000 +0000 +++ b/Objects/dictobject.c Thu Aug 31 19:04:07 2000 +0000 @@ -139,6 +139,10 @@ 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 @@ 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 @@ 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 @@ 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)
