Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Doc/c-api/reflection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions Doc/whatsnew/3.9.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions Include/cpython/frameobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
New :c:func:`PyFrame_GetBack` function: get the frame next outer frame.
12 changes: 8 additions & 4 deletions Modules/_tracemalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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;
}
}

Expand Down
10 changes: 10 additions & 0 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
18 changes: 12 additions & 6 deletions Python/_warnings.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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;
Expand All @@ -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();
Expand All @@ -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 {
Expand Down
10 changes: 6 additions & 4 deletions Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1787,22 +1787,24 @@ 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) {
_PyErr_SetString(tstate, PyExc_ValueError,
"call stack is not deep enough");
return NULL;
}
Py_INCREF(f);
return (PyObject*)f;
}

Expand Down
19 changes: 14 additions & 5 deletions Python/traceback.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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++;
}
}
Expand Down