bpo-28866: No type cache for types with specialized mro, invalidation is hard. (#13157)
* No type cache for types with specialized mro, invalidation is hard. * FIX: Don't disable method cache custom types that do not implement mro(). * fixing implem. * Avoid storing error flags, also decref. * news entry * Clear as soon as we're getting an error. * FIX: Reference leak.
This commit is contained in:
parent
135c6a56e5
commit
180dc1b0f4
|
@ -0,0 +1,2 @@
|
|||
Avoid caching attributes of classes which type defines mro() to avoid a hard
|
||||
cache invalidation problem.
|
|
@ -78,6 +78,9 @@ slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
|
|||
static void
|
||||
clear_slotdefs(void);
|
||||
|
||||
static PyObject *
|
||||
lookup_maybe_method(PyObject *self, _Py_Identifier *attrid, int *unbound);
|
||||
|
||||
/*
|
||||
* finds the beginning of the docstring's introspection signature.
|
||||
* if present, returns a pointer pointing to the first '('.
|
||||
|
@ -287,17 +290,35 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
|||
|
||||
Unset HAVE_VERSION_TAG and VALID_VERSION_TAG if the type
|
||||
has a custom MRO that includes a type which is not officially
|
||||
super type.
|
||||
super type, or if the type implements its own mro() method.
|
||||
|
||||
Called from mro_internal, which will subsequently be called on
|
||||
each subclass when their mro is recursively updated.
|
||||
*/
|
||||
Py_ssize_t i, n;
|
||||
int clear = 0;
|
||||
int custom = (Py_TYPE(type) != &PyType_Type);
|
||||
int unbound;
|
||||
PyObject *mro_meth = NULL;
|
||||
PyObject *type_mro_meth = NULL;
|
||||
|
||||
if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
|
||||
return;
|
||||
|
||||
if (custom) {
|
||||
_Py_IDENTIFIER(mro);
|
||||
mro_meth = lookup_maybe_method(
|
||||
(PyObject *)type, &PyId_mro, &unbound);
|
||||
if (mro_meth == NULL)
|
||||
goto clear;
|
||||
type_mro_meth = lookup_maybe_method(
|
||||
(PyObject *)&PyType_Type, &PyId_mro, &unbound);
|
||||
if (type_mro_meth == NULL)
|
||||
goto clear;
|
||||
if (mro_meth != type_mro_meth)
|
||||
goto clear;
|
||||
Py_XDECREF(mro_meth);
|
||||
Py_XDECREF(type_mro_meth);
|
||||
}
|
||||
n = PyTuple_GET_SIZE(bases);
|
||||
for (i = 0; i < n; i++) {
|
||||
PyObject *b = PyTuple_GET_ITEM(bases, i);
|
||||
|
@ -308,14 +329,15 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
|
|||
|
||||
if (!PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) ||
|
||||
!PyType_IsSubtype(type, cls)) {
|
||||
clear = 1;
|
||||
break;
|
||||
goto clear;
|
||||
}
|
||||
}
|
||||
|
||||
if (clear)
|
||||
type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG|
|
||||
Py_TPFLAGS_VALID_VERSION_TAG);
|
||||
return;
|
||||
clear:
|
||||
Py_XDECREF(mro_meth);
|
||||
Py_XDECREF(type_mro_meth);
|
||||
type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG|
|
||||
Py_TPFLAGS_VALID_VERSION_TAG);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
Loading…
Reference in New Issue