summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-04-29 01:28:46 (GMT)
committerGitHub <noreply@github.com>2020-04-29 01:28:46 (GMT)
commit703647732359200c54f1d2e695cc3a06b9a96c9a (patch)
treef0ccd7a79f270fe9d7c3cba896461f3f7528131b
parent66abe98a816de84f89e2de4aa78cf09056227c25 (diff)
downloadcpython-703647732359200c54f1d2e695cc3a06b9a96c9a.zip
cpython-703647732359200c54f1d2e695cc3a06b9a96c9a.tar.gz
cpython-703647732359200c54f1d2e695cc3a06b9a96c9a.tar.bz2
bpo-40421: Add PyFrame_GetBack() function (GH-19765)
New PyFrame_GetBack() function: get the frame next outer frame. Replace frame->f_back with PyFrame_GetBack(frame) in most code but frameobject.c, ceval.c and genobject.c.
-rw-r--r--Doc/c-api/reflection.rst11
-rw-r--r--Doc/whatsnew/3.9.rst1
-rw-r--r--Include/cpython/frameobject.h2
-rw-r--r--Misc/NEWS.d/next/C API/2020-04-28-19-29-36.bpo-40421.3uIIaB.rst1
-rw-r--r--Modules/_tracemalloc.c12
-rw-r--r--Objects/frameobject.c10
-rw-r--r--Python/_warnings.c18
-rw-r--r--Python/sysmodule.c10
-rw-r--r--Python/traceback.c19
9 files changed, 65 insertions, 19 deletions
diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst
index 21d9878..9207d86 100644
--- a/Doc/c-api/reflection.rst
+++ b/Doc/c-api/reflection.rst
@@ -31,6 +31,17 @@ Reflection
See also :c:func:`PyThreadState_GetFrame`.
+.. c:function:: int PyFrame_GetBack(PyFrameObject *frame)
+
+ Get the *frame* next outer frame.
+
+ Return a strong reference, or ``NULL`` if *frame* has no outer frame.
+
+ *frame* must not be ``NULL``.
+
+ .. versionadded:: 3.9
+
+
.. c:function:: int PyFrame_GetCode(PyFrameObject *frame)
Get the *frame* code.
diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst
index e26bd47..0edb114 100644
--- a/Doc/whatsnew/3.9.rst
+++ b/Doc/whatsnew/3.9.rst
@@ -538,6 +538,7 @@ Build and C API Changes
=======================
* New :c:func:`PyFrame_GetCode` function: get a frame code.
+ New :c:func:`PyFrame_GetBack` function: get the frame next outer frame.
(Contributed by Victor Stinner in :issue:`40421`.)
* Add :c:func:`PyFrame_GetLineNumber` to the limited C API.
diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h
index e32efac..36a51ba 100644
--- a/Include/cpython/frameobject.h
+++ b/Include/cpython/frameobject.h
@@ -77,6 +77,8 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
+PyAPI_FUNC(PyFrameObject *) PyFrame_GetBack(PyFrameObject *frame);
+
#ifdef __cplusplus
}
#endif
diff --git a/Misc/NEWS.d/next/C API/2020-04-28-19-29-36.bpo-40421.3uIIaB.rst b/Misc/NEWS.d/next/C API/2020-04-28-19-29-36.bpo-40421.3uIIaB.rst
new file mode 100644
index 0000000..aadfb33
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-04-28-19-29-36.bpo-40421.3uIIaB.rst
@@ -0,0 +1 @@
+New :c:func:`PyFrame_GetBack` function: get the frame next outer frame.
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index 6f28f7f..ea7e012 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -3,7 +3,7 @@
#include "pycore_pymem.h" // _Py_tracemalloc_config
#include "pycore_traceback.h"
#include "hashtable.h"
-#include "frameobject.h"
+#include "frameobject.h" // PyFrame_GetBack()
#include "clinic/_tracemalloc.c.h"
/*[clinic input]
@@ -434,15 +434,19 @@ traceback_get_frames(traceback_t *traceback)
}
PyFrameObject *pyframe = PyThreadState_GetFrame(tstate);
- Py_XDECREF(pyframe); // use a borrowed reference
- for (; pyframe != NULL; pyframe = pyframe->f_back) {
+ for (; pyframe != NULL;) {
if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
assert(traceback->frames[traceback->nframe].filename != NULL);
traceback->nframe++;
}
- if (traceback->total_nframe < UINT16_MAX)
+ if (traceback->total_nframe < UINT16_MAX) {
traceback->total_nframe++;
+ }
+
+ PyFrameObject *back = PyFrame_GetBack(pyframe);
+ Py_DECREF(pyframe);
+ pyframe = back;
}
}
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 6d288b5..451c895 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -1237,3 +1237,13 @@ PyFrame_GetCode(PyFrameObject *frame)
Py_INCREF(code);
return code;
}
+
+
+PyFrameObject*
+PyFrame_GetBack(PyFrameObject *frame)
+{
+ assert(frame != NULL);
+ PyFrameObject *back = frame->f_back;
+ Py_XINCREF(back);
+ return back;
+}
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 7c15ce0..4d65bb3 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -3,7 +3,7 @@
#include "pycore_interp.h" // PyInterpreterState.warnings
#include "pycore_pyerrors.h"
#include "pycore_pystate.h" // _PyThreadState_GET()
-#include "frameobject.h"
+#include "frameobject.h" // PyFrame_GetBack()
#include "clinic/_warnings.c.h"
#define MODULE_NAME "_warnings"
@@ -815,7 +815,9 @@ static PyFrameObject *
next_external_frame(PyFrameObject *frame)
{
do {
- frame = frame->f_back;
+ PyFrameObject *back = PyFrame_GetBack(frame);
+ Py_DECREF(frame);
+ frame = back;
} while (frame != NULL && is_internal_frame(frame));
return frame;
@@ -831,12 +833,15 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
PyObject *globals;
/* Setup globals, filename and lineno. */
- PyFrameObject *f = _PyThreadState_GET()->frame;
+ PyThreadState *tstate = _PyThreadState_GET();
+ PyFrameObject *f = PyThreadState_GetFrame(tstate);
// Stack level comparisons to Python code is off by one as there is no
// warnings-related stack level to avoid.
if (stack_level <= 0 || is_internal_frame(f)) {
while (--stack_level > 0 && f != NULL) {
- f = f->f_back;
+ PyFrameObject *back = PyFrame_GetBack(f);
+ Py_DECREF(f);
+ f = back;
}
}
else {
@@ -857,6 +862,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
Py_DECREF(code);
Py_INCREF(*filename);
*lineno = PyFrame_GetLineNumber(f);
+ Py_DECREF(f);
}
*module = NULL;
@@ -868,7 +874,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
if (*registry == NULL) {
int rc;
- if (PyErr_Occurred()) {
+ if (_PyErr_Occurred(tstate)) {
goto handle_error;
}
*registry = PyDict_New();
@@ -887,7 +893,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
if (*module == Py_None || (*module != NULL && PyUnicode_Check(*module))) {
Py_INCREF(*module);
}
- else if (PyErr_Occurred()) {
+ else if (_PyErr_Occurred(tstate)) {
goto handle_error;
}
else {
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 92ea5e7..914beb7 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -16,7 +16,7 @@ Data members:
#include "Python.h"
#include "code.h"
-#include "frameobject.h"
+#include "frameobject.h" // PyFrame_GetBack()
#include "pycore_ceval.h" // _Py_RecursionLimitLowerWaterMark()
#include "pycore_initconfig.h"
#include "pycore_object.h"
@@ -1787,14 +1787,17 @@ sys__getframe_impl(PyObject *module, int depth)
/*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/
{
PyThreadState *tstate = _PyThreadState_GET();
- PyFrameObject *f = tstate->frame;
+ PyFrameObject *f = PyThreadState_GetFrame(tstate);
if (_PySys_Audit(tstate, "sys._getframe", "O", f) < 0) {
+ Py_DECREF(f);
return NULL;
}
while (depth > 0 && f != NULL) {
- f = f->f_back;
+ PyFrameObject *back = PyFrame_GetBack(f);
+ Py_DECREF(f);
+ f = back;
--depth;
}
if (f == NULL) {
@@ -1802,7 +1805,6 @@ sys__getframe_impl(PyObject *module, int depth)
"call stack is not deep enough");
return NULL;
}
- Py_INCREF(f);
return (PyObject*)f;
}
diff --git a/Python/traceback.c b/Python/traceback.c
index 438a2c4..99b63af 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -4,7 +4,7 @@
#include "Python.h"
#include "code.h"
-#include "frameobject.h"
+#include "frameobject.h" // PyFrame_GetBack()
#include "structmember.h" // PyMemberDef
#include "osdefs.h" // SEP
#ifdef HAVE_FCNTL_H
@@ -798,22 +798,31 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
PUTS(fd, "Stack (most recent call first):\n");
}
- frame = tstate->frame;
+ frame = PyThreadState_GetFrame(tstate);
if (frame == NULL) {
PUTS(fd, "<no Python frame>\n");
return;
}
depth = 0;
- while (frame != NULL) {
+ while (1) {
if (MAX_FRAME_DEPTH <= depth) {
+ Py_DECREF(frame);
PUTS(fd, " ...\n");
break;
}
- if (!PyFrame_Check(frame))
+ if (!PyFrame_Check(frame)) {
+ Py_DECREF(frame);
break;
+ }
dump_frame(fd, frame);
- frame = frame->f_back;
+ PyFrameObject *back = PyFrame_GetBack(frame);
+ Py_DECREF(frame);
+
+ if (back == NULL) {
+ break;
+ }
+ frame = back;
depth++;
}
}