mirror of
https://github.com/python/cpython.git
synced 2025-07-24 11:44:31 +00:00
bpo-39960: Allow heap types in the "Carlo Verre" hack check that override "tp_setattro()" (GH-21092)
Automerge-Triggered-By: @gvanrossum
This commit is contained in:
parent
67673b08ea
commit
148f329135
4 changed files with 120 additions and 11 deletions
|
@ -97,6 +97,9 @@ clear_slotdefs(void);
|
|||
static PyObject *
|
||||
lookup_maybe_method(PyObject *self, _Py_Identifier *attrid, int *unbound);
|
||||
|
||||
static int
|
||||
slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value);
|
||||
|
||||
/*
|
||||
* finds the beginning of the docstring's introspection signature.
|
||||
* if present, returns a pointer pointing to the first '('.
|
||||
|
@ -5945,22 +5948,38 @@ wrap_delitem(PyObject *self, PyObject *args, void *wrapped)
|
|||
}
|
||||
|
||||
/* Helper to check for object.__setattr__ or __delattr__ applied to a type.
|
||||
This is called the Carlo Verre hack after its discoverer. */
|
||||
This is called the Carlo Verre hack after its discoverer. See
|
||||
https://mail.python.org/pipermail/python-dev/2003-April/034535.html
|
||||
*/
|
||||
static int
|
||||
hackcheck(PyObject *self, setattrofunc func, const char *what)
|
||||
{
|
||||
PyTypeObject *type = Py_TYPE(self);
|
||||
while (type && type->tp_flags & Py_TPFLAGS_HEAPTYPE)
|
||||
type = type->tp_base;
|
||||
/* If type is NULL now, this is a really weird type.
|
||||
In the spirit of backwards compatibility (?), just shut up. */
|
||||
if (type && type->tp_setattro != func) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"can't apply this %s to %s object",
|
||||
what,
|
||||
type->tp_name);
|
||||
return 0;
|
||||
PyObject *mro = type->tp_mro;
|
||||
if (!mro) {
|
||||
/* Probably ok not to check the call in this case. */
|
||||
return 1;
|
||||
}
|
||||
assert(PyTuple_Check(mro));
|
||||
Py_ssize_t i, n;
|
||||
n = PyTuple_GET_SIZE(mro);
|
||||
for (i = 0; i < n; i++) {
|
||||
PyTypeObject *base = (PyTypeObject*) PyTuple_GET_ITEM(mro, i);
|
||||
if (base->tp_setattro == func) {
|
||||
/* 'func' is the earliest non-Python implementation in the MRO. */
|
||||
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,
|
||||
"can't apply this %s to %s object",
|
||||
what,
|
||||
type->tp_name);
|
||||
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