]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-40429: PyFrame_GetCode() result cannot be NULL (GH-19772)
authorVictor Stinner <vstinner@python.org>
Tue, 28 Apr 2020 22:56:58 +0000 (00:56 +0200)
committerGitHub <noreply@github.com>
Tue, 28 Apr 2020 22:56:58 +0000 (00:56 +0200)
Add frame_nslots() to factorize duplicate code.

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

index b313ea302598e6c85c1e34a3db7fcc99753dbd25..594c1ec7943f750d9fcc5e71ccd32123fa526b83 100644 (file)
@@ -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``.
 
index 3593baee512015ddaeb83015dc01f1182c521297..b2a000302164e38140d71982cdc353b33c25b593 100644 (file)
@@ -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");
index 92206c5f521086df8c5ef94393b8b7b9c5059a0f..6b3559ee9625efb2b0e31553680327b669b3c2a1 100644 (file)
@@ -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;
 }
index 66c6ccba0c490a49357ab0f4c5701c752d6bb7fa..071def8a25aae9924151079e9c9c8438bc98ff9c 100644 (file)
@@ -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;
index 9d97f389401d459e2ccf431ab969e43c32afc58d..f65f05386cbe7a98e8cea816a76f7ba285c8062f 100644 (file)
@@ -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");
index 91c611c257305a6439665f279f3b9f8c8e5ff0dc..7a620dc54310c9c81be44d55eb155795b66a75cb 100644 (file)
@@ -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;
index c610419f24f58067be23b25bda2007101fdcf59e..e15d7e0b4603d26304cf7602e688f84de38673b6 100644 (file)
@@ -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);
 }