diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2020-07-18 21:37:43 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-18 21:37:43 (GMT) |
commit | 38d930f2ccbff6f93c4c54a7a6a1759266136504 (patch) | |
tree | 5480be9034b0bccf541d077b8979fb022bacaefc /Objects | |
parent | 668d321476d974c4f51476b33aaca870272523bf (diff) | |
download | cpython-38d930f2ccbff6f93c4c54a7a6a1759266136504.zip cpython-38d930f2ccbff6f93c4c54a7a6a1759266136504.tar.gz cpython-38d930f2ccbff6f93c4c54a7a6a1759266136504.tar.bz2 |
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
(cherry picked from commit c53b310e5926266ce267c44a168165cacd786d6e)
Co-authored-by: scoder <stefan_ml@behnel.de>
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/typeobject.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0012869..0acde71 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5822,14 +5822,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 == 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; + } + } + + /* 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 earliest non-Python implementation in the MRO. */ + /* 'func' is the right slot function to call. */ break; - } else if (base->tp_setattro != slot_tp_setattro) { + } + 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, @@ -5839,8 +5854,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; } |