[Python-checkins] bpo-40429: PyFrame_GetCode() result cannot be NULL (GH-19772)

Victor Stinner webhook-mailer at python.org
Tue Apr 28 18:57:02 EDT 2020


https://github.com/python/cpython/commit/6d86a2331e6b64a2ae80c1a21f81baa5a71ac594
commit: 6d86a2331e6b64a2ae80c1a21f81baa5a71ac594
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-04-29T00:56:58+02:00
summary:

bpo-40429: PyFrame_GetCode() result cannot be NULL (GH-19772)

Add frame_nslots() to factorize duplicate code.

files:
M Doc/c-api/reflection.rst
M Modules/_tracemalloc.c
M Objects/frameobject.c
M Objects/genobject.c
M Objects/typeobject.c
M Python/_warnings.c
M Python/ceval.c

diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index b313ea302598e..594c1ec7943f7 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -34,6 +34,7 @@ Reflection
 .. c:function:: int PyFrame_GetCode(PyFrameObject *frame)
 
    Return a borrowed reference to the *frame* code.
+   The frame code cannot be ``NULL``.
 
    *frame* must not be ``NULL``.
 
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index 3593baee51201..b2a000302164e 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -347,13 +347,6 @@ tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
     frame->lineno = (unsigned int)lineno;
 
     code = PyFrame_GetCode(pyframe);
-    if (code == NULL) {
-#ifdef TRACE_DEBUG
-        tracemalloc_error("failed to get the code object of the frame");
-#endif
-        return;
-    }
-
     if (code->co_filename == NULL) {
 #ifdef TRACE_DEBUG
         tracemalloc_error("failed to get the filename of the code object");
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 92206c5f52108..6b3559ee9625e 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -665,12 +665,18 @@ frame_dealloc(PyFrameObject *f)
     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 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
     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 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
 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 @@ frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
 {
     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 @@ static PyObject *
 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 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
     f->f_trace_opcodes = 0;
     f->f_trace_lines = 1;
 
+    assert(f->f_code != NULL);
+
     return f;
 }
 
@@ -1227,5 +1235,7 @@ PyCodeObject *
 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 66c6ccba0c490..071def8a25aae 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -1117,11 +1117,11 @@ compute_cr_origin(int origin_depth)
     }
     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 9d97f389401d4..f65f05386cbe7 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -8040,11 +8040,6 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
             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");
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 91c611c257305..7a620dc54310c 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -784,10 +784,6 @@ is_internal_frame(PyFrameObject *frame)
     }
 
     PyCodeObject *code = PyFrame_GetCode(frame);
-    if (code == NULL) {
-        return 0;
-    }
-
     PyObject *filename = code->co_filename;
     if (filename == NULL) {
         return 0;
diff --git a/Python/ceval.c b/Python/ceval.c
index c610419f24f58..e15d7e0b4603d 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -5580,9 +5580,10 @@ dtrace_function_entry(PyFrameObject *f)
     const char *funcname;
     int lineno;
 
-    filename = PyUnicode_AsUTF8(f->f_code->co_filename);
-    funcname = PyUnicode_AsUTF8(f->f_code->co_name);
-    lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+    PyCodeObject *code = f->f_code;
+    filename = PyUnicode_AsUTF8(code->co_filename);
+    funcname = PyUnicode_AsUTF8(code->co_name);
+    lineno = PyCode_Addr2Line(code, f->f_lasti);
 
     PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
 }
@@ -5594,9 +5595,10 @@ dtrace_function_return(PyFrameObject *f)
     const char *funcname;
     int lineno;
 
-    filename = PyUnicode_AsUTF8(f->f_code->co_filename);
-    funcname = PyUnicode_AsUTF8(f->f_code->co_name);
-    lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+    PyCodeObject *code = f->f_code;
+    filename = PyUnicode_AsUTF8(code->co_filename);
+    funcname = PyUnicode_AsUTF8(code->co_name);
+    lineno = PyCode_Addr2Line(code, f->f_lasti);
 
     PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
 }



More information about the Python-checkins mailing list