Commit 23094985 authored by Guido van Rossum's avatar Guido van Rossum

Three's a charm: yet another fix for SF bug 551412. Thinking again

about the test case, slot_nb_power gets called on behalf of its second
argument, but with a non-None modulus it wouldn't check this, and
believes it is called on behalf of its first argument.  Fix this
properly, and get rid of the code in _PyType_Lookup() that tries to
call _PyType_Ready().  But do leave a check for a NULL tp_mro there,
because this can still legitimately occur.

I'll fix this in 2.2.x too.
parent f70a0a84
...@@ -1309,22 +1309,13 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) ...@@ -1309,22 +1309,13 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
/* Look in tp_dict of types in MRO */ /* Look in tp_dict of types in MRO */
mro = type->tp_mro; mro = type->tp_mro;
if (mro == NULL) {
if (PyType_Ready(type) < 0) { /* If mro is NULL, the type is either not yet initialized
/* It's not ideal to clear the error condition, by PyType_Ready(), or already cleared by type_clear().
but this function is documented as not setting Either way the safest thing to do is to return NULL. */
an exception, and I don't want to change that. if (mro == NULL)
When PyType_Ready() can't proceed, it won't return NULL;
set the "ready" flag, so future attempts to ready
the same type will call it again -- hopefully
in a context that propagates the exception out.
*/
PyErr_Clear();
return NULL;
}
mro = type->tp_mro;
assert(mro != NULL);
}
assert(PyTuple_Check(mro)); assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro); n = PyTuple_GET_SIZE(mro);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
...@@ -3099,9 +3090,16 @@ slot_nb_power(PyObject *self, PyObject *other, PyObject *modulus) ...@@ -3099,9 +3090,16 @@ slot_nb_power(PyObject *self, PyObject *other, PyObject *modulus)
if (modulus == Py_None) if (modulus == Py_None)
return slot_nb_power_binary(self, other); return slot_nb_power_binary(self, other);
/* Three-arg power doesn't use __rpow__ */ /* Three-arg power doesn't use __rpow__. But ternary_op
return call_method(self, "__pow__", &pow_str, can call this when the second argument's type uses
"(OO)", other, modulus); slot_nb_power, so check before calling self.__pow__. */
if (self->ob_type->tp_as_number != NULL &&
self->ob_type->tp_as_number->nb_power == slot_nb_power) {
return call_method(self, "__pow__", &pow_str,
"(OO)", other, modulus);
}
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
} }
SLOT0(slot_nb_negative, "__neg__") SLOT0(slot_nb_negative, "__neg__")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment