From cc0dc7e484c9626857e9a8b4c40eee37473702ed Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 29 Apr 2020 02:28:23 +0200 Subject: bpo-40429: Refactor super_init() (GH-19776) Add super_init_without_args() sub-function. Hold a strong reference to the frame code object while calling super_init_without_args(). --- Objects/typeobject.c | 149 +++++++++++++++++++++++++++++---------------------- 1 file changed, 85 insertions(+), 64 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 8f9ab5c..7ba51e3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8015,6 +8015,83 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type) } static int +super_init_without_args(PyFrameObject *f, PyCodeObject *co, + PyTypeObject **type_p, PyObject **obj_p) +{ + if (co->co_argcount == 0) { + PyErr_SetString(PyExc_RuntimeError, + "super(): no arguments"); + return -1; + } + + PyObject *obj = f->f_localsplus[0]; + Py_ssize_t i, n; + if (obj == NULL && co->co_cell2arg) { + /* The first argument might be a cell. */ + n = PyTuple_GET_SIZE(co->co_cellvars); + for (i = 0; i < n; i++) { + if (co->co_cell2arg[i] == 0) { + PyObject *cell = f->f_localsplus[co->co_nlocals + i]; + assert(PyCell_Check(cell)); + obj = PyCell_GET(cell); + break; + } + } + } + if (obj == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "super(): arg[0] deleted"); + return -1; + } + + if (co->co_freevars == NULL) { + n = 0; + } + else { + assert(PyTuple_Check(co->co_freevars)); + n = PyTuple_GET_SIZE(co->co_freevars); + } + + PyTypeObject *type = NULL; + for (i = 0; i < n; i++) { + PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i); + assert(PyUnicode_Check(name)); + if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) { + Py_ssize_t index = co->co_nlocals + + PyTuple_GET_SIZE(co->co_cellvars) + i; + PyObject *cell = f->f_localsplus[index]; + if (cell == NULL || !PyCell_Check(cell)) { + PyErr_SetString(PyExc_RuntimeError, + "super(): bad __class__ cell"); + return -1; + } + type = (PyTypeObject *) PyCell_GET(cell); + if (type == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "super(): empty __class__ cell"); + return -1; + } + if (!PyType_Check(type)) { + PyErr_Format(PyExc_RuntimeError, + "super(): __class__ is not a type (%s)", + Py_TYPE(type)->tp_name); + return -1; + } + break; + } + } + if (type == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "super(): __class__ cell not found"); + return -1; + } + + *type_p = type; + *obj_p = obj; + return 0; +} + +static int super_init(PyObject *self, PyObject *args, PyObject *kwds) { superobject *su = (superobject *)self; @@ -8030,75 +8107,19 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds) if (type == NULL) { /* Call super(), without args -- fill in from __class__ and first local variable on the stack. */ - PyFrameObject *f; - Py_ssize_t i, n; - f = PyThreadState_GetFrame(_PyThreadState_GET()); + PyThreadState *tstate = _PyThreadState_GET(); + PyFrameObject *f = PyThreadState_GetFrame(tstate); if (f == NULL) { PyErr_SetString(PyExc_RuntimeError, "super(): no current frame"); return -1; } - PyCodeObject *co = PyFrame_GetCode(f); - Py_DECREF(co); // use a borrowed reference - if (co->co_argcount == 0) { - PyErr_SetString(PyExc_RuntimeError, - "super(): no arguments"); - return -1; - } - obj = f->f_localsplus[0]; - if (obj == NULL && co->co_cell2arg) { - /* The first argument might be a cell. */ - n = PyTuple_GET_SIZE(co->co_cellvars); - for (i = 0; i < n; i++) { - if (co->co_cell2arg[i] == 0) { - PyObject *cell = f->f_localsplus[co->co_nlocals + i]; - assert(PyCell_Check(cell)); - obj = PyCell_GET(cell); - break; - } - } - } - if (obj == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "super(): arg[0] deleted"); - return -1; - } - if (co->co_freevars == NULL) - n = 0; - else { - assert(PyTuple_Check(co->co_freevars)); - n = PyTuple_GET_SIZE(co->co_freevars); - } - for (i = 0; i < n; i++) { - PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i); - assert(PyUnicode_Check(name)); - if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) { - Py_ssize_t index = co->co_nlocals + - PyTuple_GET_SIZE(co->co_cellvars) + i; - PyObject *cell = f->f_localsplus[index]; - if (cell == NULL || !PyCell_Check(cell)) { - PyErr_SetString(PyExc_RuntimeError, - "super(): bad __class__ cell"); - return -1; - } - type = (PyTypeObject *) PyCell_GET(cell); - if (type == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "super(): empty __class__ cell"); - return -1; - } - if (!PyType_Check(type)) { - PyErr_Format(PyExc_RuntimeError, - "super(): __class__ is not a type (%s)", - Py_TYPE(type)->tp_name); - return -1; - } - break; - } - } - if (type == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "super(): __class__ cell not found"); + + PyCodeObject *code = PyFrame_GetCode(f); + int res = super_init_without_args(f, code, &type, &obj); + Py_DECREF(code); + + if (res < 0) { return -1; } } -- cgit v0.12