mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
66abe98a81
commit
7036477323
|
@ -31,6 +31,17 @@ Reflection
|
||||||
See also :c:func:`PyThreadState_GetFrame`.
|
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)
|
.. c:function:: int PyFrame_GetCode(PyFrameObject *frame)
|
||||||
|
|
||||||
Get the *frame* code.
|
Get the *frame* code.
|
||||||
|
|
|
@ -538,6 +538,7 @@ Build and C API Changes
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
* New :c:func:`PyFrame_GetCode` function: get a frame code.
|
* 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`.)
|
(Contributed by Victor Stinner in :issue:`40421`.)
|
||||||
|
|
||||||
* Add :c:func:`PyFrame_GetLineNumber` to the limited C API.
|
* Add :c:func:`PyFrame_GetLineNumber` to the limited C API.
|
||||||
|
|
|
@ -77,6 +77,8 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
|
||||||
|
|
||||||
PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
|
PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
|
||||||
|
|
||||||
|
PyAPI_FUNC(PyFrameObject *) PyFrame_GetBack(PyFrameObject *frame);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
New :c:func:`PyFrame_GetBack` function: get the frame next outer frame.
|
|
@ -3,7 +3,7 @@
|
||||||
#include "pycore_pymem.h" // _Py_tracemalloc_config
|
#include "pycore_pymem.h" // _Py_tracemalloc_config
|
||||||
#include "pycore_traceback.h"
|
#include "pycore_traceback.h"
|
||||||
#include "hashtable.h"
|
#include "hashtable.h"
|
||||||
#include "frameobject.h"
|
#include "frameobject.h" // PyFrame_GetBack()
|
||||||
|
|
||||||
#include "clinic/_tracemalloc.c.h"
|
#include "clinic/_tracemalloc.c.h"
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@ -434,15 +434,19 @@ traceback_get_frames(traceback_t *traceback)
|
||||||
}
|
}
|
||||||
|
|
||||||
PyFrameObject *pyframe = PyThreadState_GetFrame(tstate);
|
PyFrameObject *pyframe = PyThreadState_GetFrame(tstate);
|
||||||
Py_XDECREF(pyframe); // use a borrowed reference
|
for (; pyframe != NULL;) {
|
||||||
for (; pyframe != NULL; pyframe = pyframe->f_back) {
|
|
||||||
if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
|
if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
|
||||||
tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
|
tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
|
||||||
assert(traceback->frames[traceback->nframe].filename != NULL);
|
assert(traceback->frames[traceback->nframe].filename != NULL);
|
||||||
traceback->nframe++;
|
traceback->nframe++;
|
||||||
}
|
}
|
||||||
if (traceback->total_nframe < UINT16_MAX)
|
if (traceback->total_nframe < UINT16_MAX) {
|
||||||
traceback->total_nframe++;
|
traceback->total_nframe++;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyFrameObject *back = PyFrame_GetBack(pyframe);
|
||||||
|
Py_DECREF(pyframe);
|
||||||
|
pyframe = back;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1237,3 +1237,13 @@ PyFrame_GetCode(PyFrameObject *frame)
|
||||||
Py_INCREF(code);
|
Py_INCREF(code);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyFrameObject*
|
||||||
|
PyFrame_GetBack(PyFrameObject *frame)
|
||||||
|
{
|
||||||
|
assert(frame != NULL);
|
||||||
|
PyFrameObject *back = frame->f_back;
|
||||||
|
Py_XINCREF(back);
|
||||||
|
return back;
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "pycore_interp.h" // PyInterpreterState.warnings
|
#include "pycore_interp.h" // PyInterpreterState.warnings
|
||||||
#include "pycore_pyerrors.h"
|
#include "pycore_pyerrors.h"
|
||||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||||
#include "frameobject.h"
|
#include "frameobject.h" // PyFrame_GetBack()
|
||||||
#include "clinic/_warnings.c.h"
|
#include "clinic/_warnings.c.h"
|
||||||
|
|
||||||
#define MODULE_NAME "_warnings"
|
#define MODULE_NAME "_warnings"
|
||||||
|
@ -815,7 +815,9 @@ static PyFrameObject *
|
||||||
next_external_frame(PyFrameObject *frame)
|
next_external_frame(PyFrameObject *frame)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
frame = frame->f_back;
|
PyFrameObject *back = PyFrame_GetBack(frame);
|
||||||
|
Py_DECREF(frame);
|
||||||
|
frame = back;
|
||||||
} while (frame != NULL && is_internal_frame(frame));
|
} while (frame != NULL && is_internal_frame(frame));
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
|
@ -831,12 +833,15 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
|
||||||
PyObject *globals;
|
PyObject *globals;
|
||||||
|
|
||||||
/* Setup globals, filename and lineno. */
|
/* 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
|
// Stack level comparisons to Python code is off by one as there is no
|
||||||
// warnings-related stack level to avoid.
|
// warnings-related stack level to avoid.
|
||||||
if (stack_level <= 0 || is_internal_frame(f)) {
|
if (stack_level <= 0 || is_internal_frame(f)) {
|
||||||
while (--stack_level > 0 && f != NULL) {
|
while (--stack_level > 0 && f != NULL) {
|
||||||
f = f->f_back;
|
PyFrameObject *back = PyFrame_GetBack(f);
|
||||||
|
Py_DECREF(f);
|
||||||
|
f = back;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -857,6 +862,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
|
||||||
Py_DECREF(code);
|
Py_DECREF(code);
|
||||||
Py_INCREF(*filename);
|
Py_INCREF(*filename);
|
||||||
*lineno = PyFrame_GetLineNumber(f);
|
*lineno = PyFrame_GetLineNumber(f);
|
||||||
|
Py_DECREF(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
*module = NULL;
|
*module = NULL;
|
||||||
|
@ -868,7 +874,7 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
|
||||||
if (*registry == NULL) {
|
if (*registry == NULL) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (PyErr_Occurred()) {
|
if (_PyErr_Occurred(tstate)) {
|
||||||
goto handle_error;
|
goto handle_error;
|
||||||
}
|
}
|
||||||
*registry = PyDict_New();
|
*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))) {
|
if (*module == Py_None || (*module != NULL && PyUnicode_Check(*module))) {
|
||||||
Py_INCREF(*module);
|
Py_INCREF(*module);
|
||||||
}
|
}
|
||||||
else if (PyErr_Occurred()) {
|
else if (_PyErr_Occurred(tstate)) {
|
||||||
goto handle_error;
|
goto handle_error;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -16,7 +16,7 @@ Data members:
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "code.h"
|
#include "code.h"
|
||||||
#include "frameobject.h"
|
#include "frameobject.h" // PyFrame_GetBack()
|
||||||
#include "pycore_ceval.h" // _Py_RecursionLimitLowerWaterMark()
|
#include "pycore_ceval.h" // _Py_RecursionLimitLowerWaterMark()
|
||||||
#include "pycore_initconfig.h"
|
#include "pycore_initconfig.h"
|
||||||
#include "pycore_object.h"
|
#include "pycore_object.h"
|
||||||
|
@ -1787,14 +1787,17 @@ sys__getframe_impl(PyObject *module, int depth)
|
||||||
/*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/
|
/*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
PyFrameObject *f = tstate->frame;
|
PyFrameObject *f = PyThreadState_GetFrame(tstate);
|
||||||
|
|
||||||
if (_PySys_Audit(tstate, "sys._getframe", "O", f) < 0) {
|
if (_PySys_Audit(tstate, "sys._getframe", "O", f) < 0) {
|
||||||
|
Py_DECREF(f);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (depth > 0 && f != NULL) {
|
while (depth > 0 && f != NULL) {
|
||||||
f = f->f_back;
|
PyFrameObject *back = PyFrame_GetBack(f);
|
||||||
|
Py_DECREF(f);
|
||||||
|
f = back;
|
||||||
--depth;
|
--depth;
|
||||||
}
|
}
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
|
@ -1802,7 +1805,6 @@ sys__getframe_impl(PyObject *module, int depth)
|
||||||
"call stack is not deep enough");
|
"call stack is not deep enough");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_INCREF(f);
|
|
||||||
return (PyObject*)f;
|
return (PyObject*)f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
#include "code.h"
|
#include "code.h"
|
||||||
#include "frameobject.h"
|
#include "frameobject.h" // PyFrame_GetBack()
|
||||||
#include "structmember.h" // PyMemberDef
|
#include "structmember.h" // PyMemberDef
|
||||||
#include "osdefs.h" // SEP
|
#include "osdefs.h" // SEP
|
||||||
#ifdef HAVE_FCNTL_H
|
#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");
|
PUTS(fd, "Stack (most recent call first):\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = tstate->frame;
|
frame = PyThreadState_GetFrame(tstate);
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
PUTS(fd, "<no Python frame>\n");
|
PUTS(fd, "<no Python frame>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
depth = 0;
|
depth = 0;
|
||||||
while (frame != NULL) {
|
while (1) {
|
||||||
if (MAX_FRAME_DEPTH <= depth) {
|
if (MAX_FRAME_DEPTH <= depth) {
|
||||||
|
Py_DECREF(frame);
|
||||||
PUTS(fd, " ...\n");
|
PUTS(fd, " ...\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!PyFrame_Check(frame))
|
if (!PyFrame_Check(frame)) {
|
||||||
|
Py_DECREF(frame);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
dump_frame(fd, frame);
|
dump_frame(fd, frame);
|
||||||
frame = frame->f_back;
|
PyFrameObject *back = PyFrame_GetBack(frame);
|
||||||
|
Py_DECREF(frame);
|
||||||
|
|
||||||
|
if (back == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
frame = back;
|
||||||
depth++;
|
depth++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue