[Python-checkins] bpo-40429: PyFrame_GetCode() now returns a strong reference (GH-19773)

Victor Stinner webhook-mailer at python.org
Tue Apr 28 19:28:21 EDT 2020


https://github.com/python/cpython/commit/8852ad4208e34825f74e24945edb5bcf055d94fe
commit: 8852ad4208e34825f74e24945edb5bcf055d94fe
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-04-29T01:28:13+02:00
summary:

bpo-40429: PyFrame_GetCode() now returns a strong reference (GH-19773)

files:
M Doc/c-api/reflection.rst
M Doc/whatsnew/3.9.rst
M Modules/_lsprof.c
M Modules/_tracemalloc.c
M Objects/frameobject.c
M Objects/typeobject.c
M Python/_warnings.c
M Python/import.c
M Python/traceback.c

diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index 594c1ec7943f7..21d9878609127 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -33,10 +33,11 @@ Reflection
 
 .. c:function:: int PyFrame_GetCode(PyFrameObject *frame)
 
-   Return a borrowed reference to the *frame* code.
-   The frame code cannot be ``NULL``.
+   Get the *frame* code.
 
-   *frame* must not be ``NULL``.
+   Return a strong reference.
+
+   *frame* must not be ``NULL``. The result (frame code) cannot be ``NULL``.
 
    .. versionadded:: 3.9
 
diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst
index e3751fa168011..cb3afd593571a 100644
--- a/Doc/whatsnew/3.9.rst
+++ b/Doc/whatsnew/3.9.rst
@@ -537,8 +537,7 @@ Optimizations
 Build and C API Changes
 =======================
 
-* New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the
-  frame code.
+* New :c:func:`PyFrame_GetCode` function: get a frame code.
   (Contributed by Victor Stinner in :issue:`40421`.)
 
 * Add :c:func:`PyFrame_GetLineNumber` to the limited C API.
diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c
index 39cf6e126d635..5e53d839640d9 100644
--- a/Modules/_lsprof.c
+++ b/Modules/_lsprof.c
@@ -390,14 +390,19 @@ profiler_callback(PyObject *self, PyFrameObject *frame, int what,
     {
         PyCodeObject *code = PyFrame_GetCode(frame);
         ptrace_enter_call(self, (void *)code, (PyObject *)code);
+        Py_DECREF(code);
         break;
     }
 
     /* the 'frame' of a called function is about to finish
        (either normally or with an exception) */
     case PyTrace_RETURN:
-        ptrace_leave_call(self, (void *)PyFrame_GetCode(frame));
+    {
+        PyCodeObject *code = PyFrame_GetCode(frame);
+        ptrace_leave_call(self, (void *)code);
+        Py_DECREF(code);
         break;
+    }
 
     /* case PyTrace_EXCEPTION:
         If the exception results in the function exiting, a
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index b2a000302164e..24628a907f28a 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -335,26 +335,24 @@ hashtable_compare_traceback(_Py_hashtable_t *ht, const void *pkey,
 static void
 tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
 {
-    PyCodeObject *code;
-    PyObject *filename;
-    _Py_hashtable_entry_t *entry;
-    int lineno;
-
     frame->filename = unknown_filename;
-    lineno = PyFrame_GetLineNumber(pyframe);
-    if (lineno < 0)
+    int lineno = PyFrame_GetLineNumber(pyframe);
+    if (lineno < 0) {
         lineno = 0;
+    }
     frame->lineno = (unsigned int)lineno;
 
-    code = PyFrame_GetCode(pyframe);
-    if (code->co_filename == NULL) {
+    PyCodeObject *code = PyFrame_GetCode(pyframe);
+    PyObject *filename = code->co_filename;
+    Py_DECREF(code);
+
+    if (filename == NULL) {
 #ifdef TRACE_DEBUG
         tracemalloc_error("failed to get the filename of the code object");
 #endif
         return;
     }
 
-    filename = code->co_filename;
     assert(filename != NULL);
     if (filename == NULL)
         return;
@@ -375,6 +373,7 @@ tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
     }
 
     /* intern the filename */
+    _Py_hashtable_entry_t *entry;
     entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_filenames, filename);
     if (entry != NULL) {
         _Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_filenames, entry, filename);
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 6b3559ee9625e..533186bc046f0 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -1237,5 +1237,6 @@ PyFrame_GetCode(PyFrameObject *frame)
     assert(frame != NULL);
     PyCodeObject *code = frame->f_code;
     assert(code != NULL);
+    Py_INCREF(code);
     return code;
 }
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index f65f05386cbe7..8f9ab5c0bae62 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -8031,7 +8031,6 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
         /* Call super(), without args -- fill in from __class__
            and first local variable on the stack. */
         PyFrameObject *f;
-        PyCodeObject *co;
         Py_ssize_t i, n;
         f = PyThreadState_GetFrame(_PyThreadState_GET());
         if (f == NULL) {
@@ -8039,7 +8038,8 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
                             "super(): no current frame");
             return -1;
         }
-        co = PyFrame_GetCode(f);
+        PyCodeObject *co = PyFrame_GetCode(f);
+        Py_DECREF(co);   // use a borrowed reference
         if (co->co_argcount == 0) {
             PyErr_SetString(PyExc_RuntimeError,
                             "super(): no arguments");
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 7a620dc54310c..7c15ce0ef89c3 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -785,6 +785,8 @@ is_internal_frame(PyFrameObject *frame)
 
     PyCodeObject *code = PyFrame_GetCode(frame);
     PyObject *filename = code->co_filename;
+    Py_DECREF(code);
+
     if (filename == NULL) {
         return 0;
     }
@@ -850,7 +852,9 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
     }
     else {
         globals = f->f_globals;
-        *filename = PyFrame_GetCode(f)->co_filename;
+        PyCodeObject *code = PyFrame_GetCode(f);
+        *filename = code->co_filename;
+        Py_DECREF(code);
         Py_INCREF(*filename);
         *lineno = PyFrame_GetLineNumber(f);
     }
diff --git a/Python/import.c b/Python/import.c
index 9142ebba40dfe..8c94e0ec54655 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -1557,6 +1557,7 @@ remove_importlib_frames(PyThreadState *tstate)
         else {
             prev_link = (PyObject **) &traceback->tb_next;
         }
+        Py_DECREF(code);
         tb = next;
     }
 done:
diff --git a/Python/traceback.c b/Python/traceback.c
index 1ea6cbada964f..438a2c4fce7ca 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -581,6 +581,7 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
                 err = PyErr_CheckSignals();
             }
         }
+        Py_DECREF(code);
         tb = tb->tb_next;
     }
     if (err == 0 && cnt > TB_RECURSIVE_CUTOFF) {
@@ -752,12 +753,9 @@ _Py_DumpASCII(int fd, PyObject *text)
 static void
 dump_frame(int fd, PyFrameObject *frame)
 {
-    PyCodeObject *code;
-    int lineno;
-
-    code = PyFrame_GetCode(frame);
+    PyCodeObject *code = PyFrame_GetCode(frame);
     PUTS(fd, "  File ");
-    if (code != NULL && code->co_filename != NULL
+    if (code->co_filename != NULL
         && PyUnicode_Check(code->co_filename))
     {
         PUTS(fd, "\"");
@@ -768,7 +766,7 @@ dump_frame(int fd, PyFrameObject *frame)
     }
 
     /* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */
-    lineno = PyCode_Addr2Line(code, frame->f_lasti);
+    int lineno = PyCode_Addr2Line(code, frame->f_lasti);
     PUTS(fd, ", line ");
     if (lineno >= 0) {
         _Py_DumpDecimal(fd, (unsigned long)lineno);
@@ -778,7 +776,7 @@ dump_frame(int fd, PyFrameObject *frame)
     }
     PUTS(fd, " in ");
 
-    if (code != NULL && code->co_name != NULL
+    if (code->co_name != NULL
        && PyUnicode_Check(code->co_name)) {
         _Py_DumpASCII(fd, code->co_name);
     }
@@ -787,6 +785,7 @@ dump_frame(int fd, PyFrameObject *frame)
     }
 
     PUTS(fd, "\n");
+    Py_DECREF(code);
 }
 
 static void



More information about the Python-checkins mailing list