bpo-40429: PyFrame_GetCode() result cannot be NULL (GH-19772)
Add frame_nslots() to factorize duplicate code.
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 92206c5..6b3559e 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -665,12 +665,18 @@
Py_TRASHCAN_SAFE_END(f)
}
+static inline Py_ssize_t
+frame_nslots(PyFrameObject *frame)
+{
+ PyCodeObject *code = frame->f_code;
+ return (code->co_nlocals
+ + PyTuple_GET_SIZE(code->co_cellvars)
+ + PyTuple_GET_SIZE(code->co_freevars));
+}
+
static int
frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
{
- PyObject **fastlocals, **p;
- Py_ssize_t i, slots;
-
Py_VISIT(f->f_back);
Py_VISIT(f->f_code);
Py_VISIT(f->f_builtins);
@@ -679,15 +685,16 @@
Py_VISIT(f->f_trace);
/* locals */
- slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars);
- fastlocals = f->f_localsplus;
- for (i = slots; --i >= 0; ++fastlocals)
+ PyObject **fastlocals = f->f_localsplus;
+ for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++fastlocals) {
Py_VISIT(*fastlocals);
+ }
/* stack */
if (f->f_stacktop != NULL) {
- for (p = f->f_valuestack; p < f->f_stacktop; p++)
+ for (PyObject **p = f->f_valuestack; p < f->f_stacktop; p++) {
Py_VISIT(*p);
+ }
}
return 0;
}
@@ -695,30 +702,28 @@
static int
frame_tp_clear(PyFrameObject *f)
{
- PyObject **fastlocals, **p, **oldtop;
- Py_ssize_t i, slots;
-
/* Before anything else, make sure that this frame is clearly marked
* as being defunct! Else, e.g., a generator reachable from this
* frame may also point to this frame, believe itself to still be
* active, and try cleaning up this frame again.
*/
- oldtop = f->f_stacktop;
+ PyObject **oldtop = f->f_stacktop;
f->f_stacktop = NULL;
f->f_executing = 0;
Py_CLEAR(f->f_trace);
/* locals */
- slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars);
- fastlocals = f->f_localsplus;
- for (i = slots; --i >= 0; ++fastlocals)
+ PyObject **fastlocals = f->f_localsplus;
+ for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++fastlocals) {
Py_CLEAR(*fastlocals);
+ }
/* stack */
if (oldtop != NULL) {
- for (p = f->f_valuestack; p < oldtop; p++)
+ for (PyObject **p = f->f_valuestack; p < oldtop; p++) {
Py_CLEAR(*p);
+ }
}
return 0;
}
@@ -747,10 +752,10 @@
{
Py_ssize_t res, extras, ncells, nfrees;
- ncells = PyTuple_GET_SIZE(f->f_code->co_cellvars);
- nfrees = PyTuple_GET_SIZE(f->f_code->co_freevars);
- extras = f->f_code->co_stacksize + f->f_code->co_nlocals +
- ncells + nfrees;
+ PyCodeObject *code = f->f_code;
+ ncells = PyTuple_GET_SIZE(code->co_cellvars);
+ nfrees = PyTuple_GET_SIZE(code->co_freevars);
+ extras = code->co_stacksize + code->co_nlocals + ncells + nfrees;
/* subtract one as it is already included in PyFrameObject */
res = sizeof(PyFrameObject) + (extras-1) * sizeof(PyObject *);
@@ -764,9 +769,10 @@
frame_repr(PyFrameObject *f)
{
int lineno = PyFrame_GetLineNumber(f);
+ PyCodeObject *code = f->f_code;
return PyUnicode_FromFormat(
"<frame at %p, file %R, line %d, code %S>",
- f, f->f_code->co_filename, lineno, f->f_code->co_name);
+ f, code->co_filename, lineno, code->co_name);
}
static PyMethodDef frame_methods[] = {
@@ -940,6 +946,8 @@
f->f_trace_opcodes = 0;
f->f_trace_lines = 1;
+ assert(f->f_code != NULL);
+
return f;
}
@@ -1227,5 +1235,7 @@
PyFrame_GetCode(PyFrameObject *frame)
{
assert(frame != NULL);
- return frame->f_code;
+ PyCodeObject *code = frame->f_code;
+ assert(code != NULL);
+ return code;
}
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 66c6ccb..071def8 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -1117,11 +1117,11 @@
}
frame = PyEval_GetFrame();
for (int i = 0; i < frame_count; ++i) {
- PyObject *frameinfo = Py_BuildValue(
- "OiO",
- frame->f_code->co_filename,
- PyFrame_GetLineNumber(frame),
- frame->f_code->co_name);
+ PyCodeObject *code = frame->f_code;
+ PyObject *frameinfo = Py_BuildValue("OiO",
+ code->co_filename,
+ PyFrame_GetLineNumber(frame),
+ code->co_name);
if (!frameinfo) {
Py_DECREF(cr_origin);
return NULL;
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 9d97f38..f65f053 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -8040,11 +8040,6 @@
return -1;
}
co = PyFrame_GetCode(f);
- if (co == NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "super(): no code object");
- return -1;
- }
if (co->co_argcount == 0) {
PyErr_SetString(PyExc_RuntimeError,
"super(): no arguments");