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:
scoder 2020-07-03 02:09:28 +02:00 committed by GitHub
parent 67673b08ea
commit 148f329135
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 120 additions and 11 deletions

View file

@ -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;
}