[Python-checkins] bpo-40429: PyThreadState_GetFrame() returns a strong ref (GH-19781)

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


https://github.com/python/cpython/commit/4386b9045e5fe1151e65c2816264b5710000eb9f
commit: 4386b9045e5fe1151e65c2816264b5710000eb9f
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-04-29T03:01:43+02:00
summary:

bpo-40429: PyThreadState_GetFrame() returns a strong ref (GH-19781)

The PyThreadState_GetFrame() function now returns a strong reference
to the frame.

files:
A Misc/NEWS.d/next/C API/2020-04-29-01-39-41.bpo-40429.VQfvta.rst
M Doc/c-api/init.rst
M Modules/_tracemalloc.c
M Modules/_xxsubinterpretersmodule.c
M Objects/typeobject.c
M Python/errors.c
M Python/pystate.c

diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index afde3db30385b..68fed2acc447e 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -1074,10 +1074,10 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
 
 .. c:function:: PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
 
-   Get a borrowed reference to the current frame of the Python thread state
-   *tstate*.
+   Get the current frame of the Python thread state *tstate*.
 
-   Return ``NULL`` if no frame is currently executing.
+   Return a strong reference. Return ``NULL`` if no frame is currently
+   executing.
 
    See also :c:func:`PyEval_GetFrame`.
 
diff --git a/Misc/NEWS.d/next/C API/2020-04-29-01-39-41.bpo-40429.VQfvta.rst b/Misc/NEWS.d/next/C API/2020-04-29-01-39-41.bpo-40429.VQfvta.rst
new file mode 100644
index 0000000000000..e02aaf9003225
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-04-29-01-39-41.bpo-40429.VQfvta.rst	
@@ -0,0 +1,2 @@
+The :c:func:`PyThreadState_GetFrame` function now returns a strong reference
+to the frame.
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index 24628a907f28a..6f28f7f5757fa 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -425,10 +425,7 @@ traceback_hash(traceback_t *traceback)
 static void
 traceback_get_frames(traceback_t *traceback)
 {
-    PyThreadState *tstate;
-    PyFrameObject *pyframe;
-
-    tstate = PyGILState_GetThisThreadState();
+    PyThreadState *tstate = PyGILState_GetThisThreadState();
     if (tstate == NULL) {
 #ifdef TRACE_DEBUG
         tracemalloc_error("failed to get the current thread state");
@@ -436,7 +433,8 @@ traceback_get_frames(traceback_t *traceback)
         return;
     }
 
-    pyframe = PyThreadState_GetFrame(tstate);
+    PyFrameObject *pyframe = PyThreadState_GetFrame(tstate);
+    Py_XDECREF(pyframe); // use a borrowed reference
     for (; pyframe != NULL; pyframe = pyframe->f_back) {
         if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
             tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index e618930e09d12..15e80559ec6f6 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1840,14 +1840,17 @@ _is_running(PyInterpreterState *interp)
                         "interpreter has more than one thread");
         return -1;
     }
+
+    assert(!PyErr_Occurred());
     PyFrameObject *frame = PyThreadState_GetFrame(tstate);
     if (frame == NULL) {
-        if (PyErr_Occurred() != NULL) {
-            return -1;
-        }
         return 0;
     }
-    return (int)(frame->f_executing);
+
+    int executing = (int)(frame->f_executing);
+    Py_DECREF(frame);
+
+    return executing;
 }
 
 static int
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 7ba51e39616ca..c2ddc162ac82c 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -8108,15 +8108,16 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
         /* Call super(), without args -- fill in from __class__
            and first local variable on the stack. */
         PyThreadState *tstate = _PyThreadState_GET();
-        PyFrameObject *f = PyThreadState_GetFrame(tstate);
-        if (f == NULL) {
+        PyFrameObject *frame = PyThreadState_GetFrame(tstate);
+        if (frame == NULL) {
             PyErr_SetString(PyExc_RuntimeError,
                             "super(): no current frame");
             return -1;
         }
 
-        PyCodeObject *code = PyFrame_GetCode(f);
-        int res = super_init_without_args(f, code, &type, &obj);
+        PyCodeObject *code = PyFrame_GetCode(frame);
+        int res = super_init_without_args(frame, code, &type, &obj);
+        Py_DECREF(frame);
         Py_DECREF(code);
 
         if (res < 0) {
diff --git a/Python/errors.c b/Python/errors.c
index db007709d263e..9e53d050416ff 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -1372,7 +1372,7 @@ _PyErr_WriteUnraisableMsg(const char *err_msg_str, PyObject *obj)
     }
 
     if (exc_tb == NULL) {
-        struct _frame *frame = tstate->frame;
+        PyFrameObject *frame = tstate->frame;
         if (frame != NULL) {
             exc_tb = _PyTraceBack_FromFrame(NULL, frame);
             if (exc_tb == NULL) {
diff --git a/Python/pystate.c b/Python/pystate.c
index d6f58822b64ae..dd95750027241 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1042,11 +1042,13 @@ PyThreadState_GetInterpreter(PyThreadState *tstate)
 }
 
 
-struct _frame*
+PyFrameObject*
 PyThreadState_GetFrame(PyThreadState *tstate)
 {
     assert(tstate != NULL);
-    return tstate->frame;
+    PyFrameObject *frame = tstate->frame;
+    Py_XINCREF(frame);
+    return frame;
 }
 
 
@@ -1165,7 +1167,7 @@ _PyThread_CurrentFrames(void)
     for (i = runtime->interpreters.head; i != NULL; i = i->next) {
         PyThreadState *t;
         for (t = i->tstate_head; t != NULL; t = t->next) {
-            struct _frame *frame = t->frame;
+            PyFrameObject *frame = t->frame;
             if (frame == NULL) {
                 continue;
             }



More information about the Python-checkins mailing list