Skip to content

Commit cc0dc7e

Browse files
authored
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().
1 parent f7bbf58 commit cc0dc7e

File tree

1 file changed

+85
-64
lines changed

1 file changed

+85
-64
lines changed

Objects/typeobject.c

Lines changed: 85 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -8014,6 +8014,83 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
80148014
}
80158015
}
80168016

8017+
static int
8018+
super_init_without_args(PyFrameObject *f, PyCodeObject *co,
8019+
PyTypeObject **type_p, PyObject **obj_p)
8020+
{
8021+
if (co->co_argcount == 0) {
8022+
PyErr_SetString(PyExc_RuntimeError,
8023+
"super(): no arguments");
8024+
return -1;
8025+
}
8026+
8027+
PyObject *obj = f->f_localsplus[0];
8028+
Py_ssize_t i, n;
8029+
if (obj == NULL && co->co_cell2arg) {
8030+
/* The first argument might be a cell. */
8031+
n = PyTuple_GET_SIZE(co->co_cellvars);
8032+
for (i = 0; i < n; i++) {
8033+
if (co->co_cell2arg[i] == 0) {
8034+
PyObject *cell = f->f_localsplus[co->co_nlocals + i];
8035+
assert(PyCell_Check(cell));
8036+
obj = PyCell_GET(cell);
8037+
break;
8038+
}
8039+
}
8040+
}
8041+
if (obj == NULL) {
8042+
PyErr_SetString(PyExc_RuntimeError,
8043+
"super(): arg[0] deleted");
8044+
return -1;
8045+
}
8046+
8047+
if (co->co_freevars == NULL) {
8048+
n = 0;
8049+
}
8050+
else {
8051+
assert(PyTuple_Check(co->co_freevars));
8052+
n = PyTuple_GET_SIZE(co->co_freevars);
8053+
}
8054+
8055+
PyTypeObject *type = NULL;
8056+
for (i = 0; i < n; i++) {
8057+
PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
8058+
assert(PyUnicode_Check(name));
8059+
if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) {
8060+
Py_ssize_t index = co->co_nlocals +
8061+
PyTuple_GET_SIZE(co->co_cellvars) + i;
8062+
PyObject *cell = f->f_localsplus[index];
8063+
if (cell == NULL || !PyCell_Check(cell)) {
8064+
PyErr_SetString(PyExc_RuntimeError,
8065+
"super(): bad __class__ cell");
8066+
return -1;
8067+
}
8068+
type = (PyTypeObject *) PyCell_GET(cell);
8069+
if (type == NULL) {
8070+
PyErr_SetString(PyExc_RuntimeError,
8071+
"super(): empty __class__ cell");
8072+
return -1;
8073+
}
8074+
if (!PyType_Check(type)) {
8075+
PyErr_Format(PyExc_RuntimeError,
8076+
"super(): __class__ is not a type (%s)",
8077+
Py_TYPE(type)->tp_name);
8078+
return -1;
8079+
}
8080+
break;
8081+
}
8082+
}
8083+
if (type == NULL) {
8084+
PyErr_SetString(PyExc_RuntimeError,
8085+
"super(): __class__ cell not found");
8086+
return -1;
8087+
}
8088+
8089+
*type_p = type;
8090+
*obj_p = obj;
8091+
return 0;
8092+
}
8093+
80178094
static int
80188095
super_init(PyObject *self, PyObject *args, PyObject *kwds)
80198096
{
@@ -8030,75 +8107,19 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
80308107
if (type == NULL) {
80318108
/* Call super(), without args -- fill in from __class__
80328109
and first local variable on the stack. */
8033-
PyFrameObject *f;
8034-
Py_ssize_t i, n;
8035-
f = PyThreadState_GetFrame(_PyThreadState_GET());
8110+
PyThreadState *tstate = _PyThreadState_GET();
8111+
PyFrameObject *f = PyThreadState_GetFrame(tstate);
80368112
if (f == NULL) {
80378113
PyErr_SetString(PyExc_RuntimeError,
80388114
"super(): no current frame");
80398115
return -1;
80408116
}
8041-
PyCodeObject *co = PyFrame_GetCode(f);
8042-
Py_DECREF(co); // use a borrowed reference
8043-
if (co->co_argcount == 0) {
8044-
PyErr_SetString(PyExc_RuntimeError,
8045-
"super(): no arguments");
8046-
return -1;
8047-
}
8048-
obj = f->f_localsplus[0];
8049-
if (obj == NULL && co->co_cell2arg) {
8050-
/* The first argument might be a cell. */
8051-
n = PyTuple_GET_SIZE(co->co_cellvars);
8052-
for (i = 0; i < n; i++) {
8053-
if (co->co_cell2arg[i] == 0) {
8054-
PyObject *cell = f->f_localsplus[co->co_nlocals + i];
8055-
assert(PyCell_Check(cell));
8056-
obj = PyCell_GET(cell);
8057-
break;
8058-
}
8059-
}
8060-
}
8061-
if (obj == NULL) {
8062-
PyErr_SetString(PyExc_RuntimeError,
8063-
"super(): arg[0] deleted");
8064-
return -1;
8065-
}
8066-
if (co->co_freevars == NULL)
8067-
n = 0;
8068-
else {
8069-
assert(PyTuple_Check(co->co_freevars));
8070-
n = PyTuple_GET_SIZE(co->co_freevars);
8071-
}
8072-
for (i = 0; i < n; i++) {
8073-
PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
8074-
assert(PyUnicode_Check(name));
8075-
if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) {
8076-
Py_ssize_t index = co->co_nlocals +
8077-
PyTuple_GET_SIZE(co->co_cellvars) + i;
8078-
PyObject *cell = f->f_localsplus[index];
8079-
if (cell == NULL || !PyCell_Check(cell)) {
8080-
PyErr_SetString(PyExc_RuntimeError,
8081-
"super(): bad __class__ cell");
8082-
return -1;
8083-
}
8084-
type = (PyTypeObject *) PyCell_GET(cell);
8085-
if (type == NULL) {
8086-
PyErr_SetString(PyExc_RuntimeError,
8087-
"super(): empty __class__ cell");
8088-
return -1;
8089-
}
8090-
if (!PyType_Check(type)) {
8091-
PyErr_Format(PyExc_RuntimeError,
8092-
"super(): __class__ is not a type (%s)",
8093-
Py_TYPE(type)->tp_name);
8094-
return -1;
8095-
}
8096-
break;
8097-
}
8098-
}
8099-
if (type == NULL) {
8100-
PyErr_SetString(PyExc_RuntimeError,
8101-
"super(): __class__ cell not found");
8117+
8118+
PyCodeObject *code = PyFrame_GetCode(f);
8119+
int res = super_init_without_args(f, code, &type, &obj);
8120+
Py_DECREF(code);
8121+
8122+
if (res < 0) {
81028123
return -1;
81038124
}
81048125
}

0 commit comments

Comments
 (0)