xref: /third_party/python/Python/frame.c (revision 7db96d56)
1
2#include "Python.h"
3#include "frameobject.h"
4#include "pycore_code.h"          // stats
5#include "pycore_frame.h"
6#include "pycore_object.h"        // _PyObject_GC_UNTRACK()
7#include "opcode.h"
8
9int
10_PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg)
11{
12    Py_VISIT(frame->frame_obj);
13    Py_VISIT(frame->f_locals);
14    Py_VISIT(frame->f_func);
15    Py_VISIT(frame->f_code);
16   /* locals */
17    PyObject **locals = _PyFrame_GetLocalsArray(frame);
18    int i = 0;
19    /* locals and stack */
20    for (; i <frame->stacktop; i++) {
21        Py_VISIT(locals[i]);
22    }
23    return 0;
24}
25
26PyFrameObject *
27_PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
28{
29    assert(frame->frame_obj == NULL);
30    PyObject *error_type, *error_value, *error_traceback;
31    PyErr_Fetch(&error_type, &error_value, &error_traceback);
32
33    PyFrameObject *f = _PyFrame_New_NoTrack(frame->f_code);
34    if (f == NULL) {
35        Py_XDECREF(error_type);
36        Py_XDECREF(error_value);
37        Py_XDECREF(error_traceback);
38        return NULL;
39    }
40    PyErr_Restore(error_type, error_value, error_traceback);
41    if (frame->frame_obj) {
42        // GH-97002: How did we get into this horrible situation? Most likely,
43        // allocating f triggered a GC collection, which ran some code that
44        // *also* created the same frame... while we were in the middle of
45        // creating it! See test_sneaky_frame_object in test_frame.py for a
46        // concrete example.
47        //
48        // Regardless, just throw f away and use that frame instead, since it's
49        // already been exposed to user code. It's actually a bit tricky to do
50        // this, since we aren't backed by a real _PyInterpreterFrame anymore.
51        // Just pretend that we have an owned, cleared frame so frame_dealloc
52        // doesn't make the situation worse:
53        f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data;
54        f->f_frame->owner = FRAME_CLEARED;
55        f->f_frame->frame_obj = f;
56        Py_DECREF(f);
57        return frame->frame_obj;
58    }
59    assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
60    assert(frame->owner != FRAME_CLEARED);
61    f->f_frame = frame;
62    frame->frame_obj = f;
63    return f;
64}
65
66void
67_PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest)
68{
69    assert(src->stacktop >= src->f_code->co_nlocalsplus);
70    Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src;
71    memcpy(dest, src, size);
72    // Don't leave a dangling pointer to the old frame when creating generators
73    // and coroutines:
74    dest->previous = NULL;
75}
76
77
78static void
79take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
80{
81    assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
82    assert(frame->owner != FRAME_CLEARED);
83    Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
84    memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size);
85    frame = (_PyInterpreterFrame *)f->_f_frame_data;
86    f->f_frame = frame;
87    frame->owner = FRAME_OWNED_BY_FRAME_OBJECT;
88    if (_PyFrame_IsIncomplete(frame)) {
89        // This may be a newly-created generator or coroutine frame. Since it's
90        // dead anyways, just pretend that the first RESUME ran:
91        PyCodeObject *code = frame->f_code;
92        frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable;
93    }
94    assert(!_PyFrame_IsIncomplete(frame));
95    assert(f->f_back == NULL);
96    _PyInterpreterFrame *prev = frame->previous;
97    while (prev && _PyFrame_IsIncomplete(prev)) {
98        prev = prev->previous;
99    }
100    if (prev) {
101        /* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */
102        PyFrameObject *back = _PyFrame_GetFrameObject(prev);
103        if (back == NULL) {
104            /* Memory error here. */
105            assert(PyErr_ExceptionMatches(PyExc_MemoryError));
106            /* Nothing we can do about it */
107            PyErr_Clear();
108        }
109        else {
110            f->f_back = (PyFrameObject *)Py_NewRef(back);
111        }
112        frame->previous = NULL;
113    }
114    if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) {
115        _PyObject_GC_TRACK((PyObject *)f);
116    }
117}
118
119void
120_PyFrame_Clear(_PyInterpreterFrame *frame)
121{
122    /* It is the responsibility of the owning generator/coroutine
123     * to have cleared the enclosing generator, if any. */
124    assert(frame->owner != FRAME_OWNED_BY_GENERATOR ||
125        _PyFrame_GetGenerator(frame)->gi_frame_state == FRAME_CLEARED);
126    // GH-99729: Clearing this frame can expose the stack (via finalizers). It's
127    // crucial that this frame has been unlinked, and is no longer visible:
128    assert(_PyThreadState_GET()->cframe->current_frame != frame);
129    if (frame->frame_obj) {
130        PyFrameObject *f = frame->frame_obj;
131        frame->frame_obj = NULL;
132        if (Py_REFCNT(f) > 1) {
133            take_ownership(f, frame);
134            Py_DECREF(f);
135            return;
136        }
137        Py_DECREF(f);
138    }
139    assert(frame->stacktop >= 0);
140    for (int i = 0; i < frame->stacktop; i++) {
141        Py_XDECREF(frame->localsplus[i]);
142    }
143    Py_XDECREF(frame->frame_obj);
144    Py_XDECREF(frame->f_locals);
145    Py_DECREF(frame->f_func);
146    Py_DECREF(frame->f_code);
147}
148
149/* Consumes reference to func */
150_PyInterpreterFrame *
151_PyFrame_Push(PyThreadState *tstate, PyFunctionObject *func)
152{
153    PyCodeObject *code = (PyCodeObject *)func->func_code;
154    size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
155    CALL_STAT_INC(frames_pushed);
156    _PyInterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size);
157    if (new_frame == NULL) {
158        Py_DECREF(func);
159        return NULL;
160    }
161    _PyFrame_InitializeSpecials(new_frame, func, NULL, code->co_nlocalsplus);
162    return new_frame;
163}
164
165int
166_PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame)
167{
168    int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
169    return PyCode_Addr2Line(frame->f_code, addr);
170}
171