Coverage Report

Created: 2025-10-10 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Python/frame.c
Line
Count
Source
1
#define _PY_INTERPRETER
2
3
#include "Python.h"
4
#include "pycore_frame.h"         // _PyFrame_New_NoTrack()
5
#include "pycore_interpframe.h"   // _PyFrame_GetCode()
6
#include "pycore_genobject.h"     // _PyGen_GetGeneratorFromFrame()
7
#include "pycore_stackref.h"      // _Py_VISIT_STACKREF()
8
9
10
int
11
_PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg)
12
663k
{
13
663k
    Py_VISIT(frame->frame_obj);
14
663k
    Py_VISIT(frame->f_locals);
15
663k
    _Py_VISIT_STACKREF(frame->f_funcobj);
16
663k
    _Py_VISIT_STACKREF(frame->f_executable);
17
663k
    return _PyGC_VisitFrameStack(frame, visit, arg);
18
663k
}
19
20
PyFrameObject *
21
_PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
22
23.1M
{
23
23.1M
    assert(frame->frame_obj == NULL);
24
23.1M
    PyObject *exc = PyErr_GetRaisedException();
25
26
23.1M
    PyFrameObject *f = _PyFrame_New_NoTrack(_PyFrame_GetCode(frame));
27
23.1M
    if (f == NULL) {
28
0
        Py_XDECREF(exc);
29
0
        return NULL;
30
0
    }
31
23.1M
    PyErr_SetRaisedException(exc);
32
33
    // GH-97002: There was a time when a frame object could be created when we
34
    // are allocating the new frame object f above, so frame->frame_obj would
35
    // be assigned already. That path does not exist anymore. We won't call any
36
    // Python code in this function and garbage collection will not run.
37
    // Notice that _PyFrame_New_NoTrack() can potentially raise a MemoryError,
38
    // but it won't allocate a traceback until the frame unwinds, so we are safe
39
    // here.
40
23.1M
    assert(frame->frame_obj == NULL);
41
23.1M
    assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
42
23.1M
    f->f_frame = frame;
43
23.1M
    frame->frame_obj = f;
44
23.1M
    return f;
45
23.1M
}
46
47
static void
48
take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
49
11.7M
{
50
11.7M
    Py_BEGIN_CRITICAL_SECTION(f);
51
11.7M
    assert(frame->owner < FRAME_OWNED_BY_INTERPRETER);
52
11.7M
    assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
53
11.7M
    _PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)f->_f_frame_data;
54
11.7M
    _PyFrame_Copy(frame, new_frame);
55
    // _PyFrame_Copy takes the reference to the executable,
56
    // so we need to restore it.
57
11.7M
    frame->f_executable = PyStackRef_DUP(new_frame->f_executable);
58
11.7M
    f->f_frame = new_frame;
59
11.7M
    new_frame->owner = FRAME_OWNED_BY_FRAME_OBJECT;
60
11.7M
    if (_PyFrame_IsIncomplete(new_frame)) {
61
        // This may be a newly-created generator or coroutine frame. Since it's
62
        // dead anyways, just pretend that the first RESUME ran:
63
0
        PyCodeObject *code = _PyFrame_GetCode(new_frame);
64
0
        new_frame->instr_ptr =
65
0
            _PyFrame_GetBytecode(new_frame) + code->_co_firsttraceable + 1;
66
0
    }
67
11.7M
    assert(!_PyFrame_IsIncomplete(new_frame));
68
11.7M
    assert(f->f_back == NULL);
69
11.7M
    _PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous);
70
11.7M
    if (prev) {
71
11.7M
        assert(prev->owner < FRAME_OWNED_BY_INTERPRETER);
72
11.7M
        PyObject *exc = PyErr_GetRaisedException();
73
        /* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */
74
11.7M
        PyFrameObject *back = _PyFrame_GetFrameObject(prev);
75
11.7M
        if (back == NULL) {
76
            /* Memory error here. */
77
0
            assert(PyErr_ExceptionMatches(PyExc_MemoryError));
78
            /* Nothing we can do about it */
79
0
            PyErr_Clear();
80
0
        }
81
11.7M
        else {
82
11.7M
            f->f_back = (PyFrameObject *)Py_NewRef(back);
83
11.7M
        }
84
11.7M
        PyErr_SetRaisedException(exc);
85
11.7M
    }
86
11.7M
    if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) {
87
11.7M
        _PyObject_GC_TRACK((PyObject *)f);
88
11.7M
    }
89
11.7M
    Py_END_CRITICAL_SECTION();
90
11.7M
}
91
92
void
93
_PyFrame_ClearLocals(_PyInterpreterFrame *frame)
94
484M
{
95
484M
    assert(frame->stackpointer != NULL);
96
484M
    _PyStackRef *sp = frame->stackpointer;
97
484M
    _PyStackRef *locals = frame->localsplus;
98
484M
    frame->stackpointer = locals;
99
2.10G
    while (sp > locals) {
100
1.62G
        sp--;
101
1.62G
        PyStackRef_XCLOSE(*sp);
102
1.62G
    }
103
484M
    Py_CLEAR(frame->f_locals);
104
484M
}
105
106
void
107
_PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
108
496M
{
109
    /* It is the responsibility of the owning generator/coroutine
110
     * to have cleared the enclosing generator, if any. */
111
496M
    assert(frame->owner != FRAME_OWNED_BY_GENERATOR ||
112
496M
        _PyGen_GetGeneratorFromFrame(frame)->gi_frame_state == FRAME_CLEARED);
113
    // GH-99729: Clearing this frame can expose the stack (via finalizers). It's
114
    // crucial that this frame has been unlinked, and is no longer visible:
115
496M
    assert(_PyThreadState_GET()->current_frame != frame);
116
496M
    if (frame->frame_obj) {
117
23.1M
        PyFrameObject *f = frame->frame_obj;
118
23.1M
        frame->frame_obj = NULL;
119
23.1M
        if (!_PyObject_IsUniquelyReferenced((PyObject *)f)) {
120
11.7M
            take_ownership(f, frame);
121
11.7M
            Py_DECREF(f);
122
11.7M
            return;
123
11.7M
        }
124
11.4M
        Py_DECREF(f);
125
11.4M
    }
126
484M
    _PyFrame_ClearLocals(frame);
127
484M
    PyStackRef_CLEAR(frame->f_funcobj);
128
484M
}
129
130
/* Unstable API functions */
131
132
PyObject *
133
PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)
134
0
{
135
0
    return PyStackRef_AsPyObjectNew(frame->f_executable);
136
0
}
137
138
int
139
PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)
140
0
{
141
0
    return _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
142
0
}
143
144
// NOTE: We allow racy accesses to the instruction pointer from other threads
145
// for sys._current_frames() and similar APIs.
146
int _Py_NO_SANITIZE_THREAD
147
PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame)
148
2.19k
{
149
2.19k
    int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
150
2.19k
    return PyCode_Addr2Line(_PyFrame_GetCode(frame), addr);
151
2.19k
}
152
153
const PyTypeObject *const PyUnstable_ExecutableKinds[PyUnstable_EXECUTABLE_KINDS+1] = {
154
    [PyUnstable_EXECUTABLE_KIND_SKIP] = &_PyNone_Type,
155
    [PyUnstable_EXECUTABLE_KIND_PY_FUNCTION] = &PyCode_Type,
156
    [PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION] = &PyMethod_Type,
157
    [PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR] = &PyMethodDescr_Type,
158
    [PyUnstable_EXECUTABLE_KINDS] = NULL,
159
};