Coverage Report

Created: 2026-10-17 06:15

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