mirror of
https://github.com/python/cpython.git
synced 2025-11-25 21:11:09 +00:00
bpo-41295: Reimplement the Carlo Verre "hackcheck" (GH-21528)
Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call. Automerge-Triggered-By: @gvanrossum
This commit is contained in:
parent
8ca8a2e8fb
commit
c53b310e59
3 changed files with 60 additions and 8 deletions
|
|
@ -5961,14 +5961,29 @@ hackcheck(PyObject *self, setattrofunc func, const char *what)
|
|||
return 1;
|
||||
}
|
||||
assert(PyTuple_Check(mro));
|
||||
Py_ssize_t i, n;
|
||||
n = PyTuple_GET_SIZE(mro);
|
||||
for (i = 0; i < n; i++) {
|
||||
|
||||
/* Find the (base) type that defined the type's slot function. */
|
||||
PyTypeObject *defining_type = type;
|
||||
Py_ssize_t i;
|
||||
for (i = PyTuple_GET_SIZE(mro) - 1; i >= 0; i--) {
|
||||
PyTypeObject *base = (PyTypeObject*) PyTuple_GET_ITEM(mro, i);
|
||||
if (base->tp_setattro == func) {
|
||||
/* 'func' is the earliest non-Python implementation in the MRO. */
|
||||
if (base->tp_setattro == slot_tp_setattro) {
|
||||
/* Ignore Python classes:
|
||||
they never define their own C-level setattro. */
|
||||
}
|
||||
else if (base->tp_setattro == type->tp_setattro) {
|
||||
defining_type = base;
|
||||
break;
|
||||
} else if (base->tp_setattro != slot_tp_setattro) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Reject calls that jump over intermediate C-level overrides. */
|
||||
for (PyTypeObject *base = defining_type; base; base = base->tp_base) {
|
||||
if (base->tp_setattro == func) {
|
||||
/* 'func' is the right slot function to call. */
|
||||
break;
|
||||
}
|
||||
else if (base->tp_setattro != slot_tp_setattro) {
|
||||
/* 'base' is not a Python class and overrides 'func'.
|
||||
Its tp_setattro should be called instead. */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
|
|
@ -5978,8 +5993,6 @@ hackcheck(PyObject *self, setattrofunc func, const char *what)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
/* Either 'func' is not in the mro (which should fail when checking 'self'),
|
||||
or it's the right slot function to call. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue