LCOV - code coverage report
Current view: | top level - Python - frame.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 58 | 68 | 85.3 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 6 | 6 | 100.0 %
|  |  | Branches: | 24 | 40 | 60.0 %

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

Generated by: LCOV version 1.14