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:
Victor Stinner 2020-04-29 03:28:46 +02:00 committed by GitHub
parent 66abe98a81
commit 7036477323
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 65 additions and 19 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -0,0 +1 @@
New :c:func:`PyFrame_GetBack` function: get the frame next outer frame.

View File

@ -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;
} }
} }

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;
} }

View File

@ -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++;
} }
} }