bpo-40429: PyThreadState_GetFrame() returns a strong ref (GH-19781)
The PyThreadState_GetFrame() function now returns a strong reference
to the frame.
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index afde3db..68fed2a 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -1074,10 +1074,10 @@
.. 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 0000000..e02aaf9
--- /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 24628a9..6f28f7f 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -425,10 +425,7 @@
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 @@
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 e618930..15e8055 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1840,14 +1840,17 @@
"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 7ba51e3..c2ddc16 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -8108,15 +8108,16 @@
/* 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 db00770..9e53d05 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -1372,7 +1372,7 @@
}
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 d6f5882..dd95750 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1042,11 +1042,13 @@
}
-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 @@
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;
}