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.
This commit is contained in:
parent
a3895c0d29
commit
c88b99ce06
@ -139,6 +139,10 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
|
|||||||
register unsigned int mask = mp->ma_size-1;
|
register unsigned int mask = mp->ma_size-1;
|
||||||
dictentry *ep0 = mp->ma_table;
|
dictentry *ep0 = mp->ma_table;
|
||||||
register dictentry *ep;
|
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
|
/* 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 */
|
and 0 < incr < ma_size and both are a function of hash */
|
||||||
i = (~hash) & mask;
|
i = (~hash) & mask;
|
||||||
@ -151,14 +155,25 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
|
|||||||
if (ep->me_key == dummy)
|
if (ep->me_key == dummy)
|
||||||
freeslot = ep;
|
freeslot = ep;
|
||||||
else {
|
else {
|
||||||
if (ep->me_hash == hash &&
|
if (ep->me_hash == hash) {
|
||||||
PyObject_Compare(ep->me_key, key) == 0)
|
/* error can't have been checked yet */
|
||||||
{
|
checked_error = 1;
|
||||||
return ep;
|
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;
|
freeslot = NULL;
|
||||||
}
|
}
|
||||||
/* XXX What if PyObject_Compare returned an exception? */
|
|
||||||
/* Derive incr from hash, just to make it more arbitrary. Note that
|
/* 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 must not be 0, or we will get into an infinite loop.*/
|
||||||
incr = (hash ^ ((unsigned long)hash >> 3)) & mask;
|
incr = (hash ^ ((unsigned long)hash >> 3)) & mask;
|
||||||
@ -167,6 +182,8 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
ep = &ep0[(i+incr)&mask];
|
ep = &ep0[(i+incr)&mask];
|
||||||
if (ep->me_key == NULL) {
|
if (ep->me_key == NULL) {
|
||||||
|
if (restore_error)
|
||||||
|
PyErr_Restore(err_type, err_value, err_tb);
|
||||||
if (freeslot != NULL)
|
if (freeslot != NULL)
|
||||||
return freeslot;
|
return freeslot;
|
||||||
else
|
else
|
||||||
@ -176,12 +193,30 @@ lookdict(dictobject *mp, PyObject *key, register long hash)
|
|||||||
if (freeslot == NULL)
|
if (freeslot == NULL)
|
||||||
freeslot = ep;
|
freeslot = ep;
|
||||||
}
|
}
|
||||||
else if (ep->me_key == key ||
|
else if (ep->me_key == key) {
|
||||||
(ep->me_hash == hash &&
|
if (restore_error)
|
||||||
PyObject_Compare(ep->me_key, key) == 0)) {
|
PyErr_Restore(err_type, err_value, err_tb);
|
||||||
return ep;
|
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} */
|
/* Cycle through GF(2^n)-{0} */
|
||||||
incr = incr << 1;
|
incr = incr << 1;
|
||||||
if (incr > mask)
|
if (incr > mask)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user