]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-40421: Add PyFrame_GetBack() function (GH-19765)
authorVictor Stinner <vstinner@python.org>
Wed, 29 Apr 2020 01:28:46 +0000 (03:28 +0200)
committerGitHub <noreply@github.com>
Wed, 29 Apr 2020 01:28:46 +0000 (03:28 +0200)
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.

Doc/c-api/reflection.rst
Doc/whatsnew/3.9.rst
Include/cpython/frameobject.h
Misc/NEWS.d/next/C API/2020-04-28-19-29-36.bpo-40421.3uIIaB.rst [new file with mode: 0644]
Modules/_tracemalloc.c
Objects/frameobject.c
Python/_warnings.c
Python/sysmodule.c
Python/traceback.c

index 21d9878609127182368139203bfd7bd779dd7aa1..9207d86012c8b338175ba72b849510b7d8edb8c4 100644 (file)
@@ -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.
index e26bd473e6189dd291f30cedf0a42d88b4c45fb8..0edb11419c43cd6079a404c1464f0f9731391b5b 100644 (file)
@@ -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.
index e32efac594718160c399f1c1497ceffd7358d330..36a51baae8784bae26ab18169dce77ed4780edf9 100644 (file)
@@ -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 (file)
index 0000000..aadfb33
--- /dev/null
@@ -0,0 +1 @@
+New :c:func:`PyFrame_GetBack` function: get the frame next outer frame.
index 6f28f7f5757fa6cb1d95872bfda1d5ef43dc174a..ea7e0127366ab0a04313b72dff38dacade636c52 100644 (file)
@@ -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;
     }
 }
 
index 6d288b5b059d7ae500fe9362c411aeed93f94933..451c895a77c6b13beed16043791d9408c9ddd838 100644 (file)
@@ -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;
+}
index 7c15ce0ef89c347908835ec64f7fb5e5429655e8..4d65bb30c8e5cdb2b84a951e9718a1c869ba6cc6 100644 (file)
@@ -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 {
index 92ea5e7d637b9441406324f06a7621d86e49c103..914beb7e127fe14daaff4173f25c0f6939b126c8 100644 (file)
@@ -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;
 }
 
index 438a2c4fce7ca7edb08f300956104682dcb6f5de..99b63af11f8beec518173d59be570d7944417f20 100644 (file)
@@ -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++;
     }
 }