0
0
mirror of https://github.com/python/cpython.git synced 2024-11-24 08:52:25 +01:00
cpython/Python/frame.c
Irit Katriel 1f16b4ce56
gh-118272: Clear generator frame's locals when the generator is closed (#118277)
Co-authored-by: Thomas Grainger <tagrain@gmail.com>
2024-04-30 19:32:25 +01:00

162 lines
5.3 KiB
C

#define _PY_INTERPRETER
#include "Python.h"
#include "frameobject.h"
#include "pycore_code.h" // stats
#include "pycore_frame.h"
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "opcode.h"
int
_PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg)
{
Py_VISIT(frame->frame_obj);
Py_VISIT(frame->f_locals);
Py_VISIT(frame->f_funcobj);
Py_VISIT(_PyFrame_GetCode(frame));
/* locals */
PyObject **locals = _PyFrame_GetLocalsArray(frame);
int i = 0;
/* locals and stack */
for (; i <frame->stacktop; i++) {
Py_VISIT(locals[i]);
}
return 0;
}
PyFrameObject *
_PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
{
assert(frame->frame_obj == NULL);
PyObject *exc = PyErr_GetRaisedException();
PyFrameObject *f = _PyFrame_New_NoTrack(_PyFrame_GetCode(frame));
if (f == NULL) {
Py_XDECREF(exc);
return NULL;
}
PyErr_SetRaisedException(exc);
// GH-97002: There was a time when a frame object could be created when we
// are allocating the new frame object f above, so frame->frame_obj would
// be assigned already. That path does not exist anymore. We won't call any
// Python code in this function and garbage collection will not run.
// Notice that _PyFrame_New_NoTrack() can potentially raise a MemoryError,
// but it won't allocate a traceback until the frame unwinds, so we are safe
// here.
assert(frame->frame_obj == NULL);
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
assert(frame->owner != FRAME_CLEARED);
f->f_frame = frame;
frame->frame_obj = f;
return f;
}
static void
take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
{
assert(frame->owner != FRAME_OWNED_BY_CSTACK);
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
assert(frame->owner != FRAME_CLEARED);
Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
Py_INCREF(_PyFrame_GetCode(frame));
memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size);
frame = (_PyInterpreterFrame *)f->_f_frame_data;
f->f_frame = frame;
frame->owner = FRAME_OWNED_BY_FRAME_OBJECT;
if (_PyFrame_IsIncomplete(frame)) {
// This may be a newly-created generator or coroutine frame. Since it's
// dead anyways, just pretend that the first RESUME ran:
PyCodeObject *code = _PyFrame_GetCode(frame);
frame->instr_ptr = _PyCode_CODE(code) + code->_co_firsttraceable + 1;
}
assert(!_PyFrame_IsIncomplete(frame));
assert(f->f_back == NULL);
_PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous);
frame->previous = NULL;
if (prev) {
assert(prev->owner != FRAME_OWNED_BY_CSTACK);
/* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */
PyFrameObject *back = _PyFrame_GetFrameObject(prev);
if (back == NULL) {
/* Memory error here. */
assert(PyErr_ExceptionMatches(PyExc_MemoryError));
/* Nothing we can do about it */
PyErr_Clear();
}
else {
f->f_back = (PyFrameObject *)Py_NewRef(back);
}
}
if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) {
_PyObject_GC_TRACK((PyObject *)f);
}
}
void
_PyFrame_ClearLocals(_PyInterpreterFrame *frame)
{
assert(frame->stacktop >= 0);
for (int i = 0; i < frame->stacktop; i++) {
Py_XDECREF(frame->localsplus[i]);
}
frame->stacktop = 0;
Py_CLEAR(frame->f_locals);
}
void
_PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
{
/* It is the responsibility of the owning generator/coroutine
* to have cleared the enclosing generator, if any. */
assert(frame->owner != FRAME_OWNED_BY_GENERATOR ||
_PyFrame_GetGenerator(frame)->gi_frame_state == FRAME_CLEARED);
// GH-99729: Clearing this frame can expose the stack (via finalizers). It's
// crucial that this frame has been unlinked, and is no longer visible:
assert(_PyThreadState_GET()->current_frame != frame);
if (frame->frame_obj) {
PyFrameObject *f = frame->frame_obj;
frame->frame_obj = NULL;
if (Py_REFCNT(f) > 1) {
take_ownership(f, frame);
Py_DECREF(f);
return;
}
Py_DECREF(f);
}
_PyFrame_ClearLocals(frame);
Py_DECREF(frame->f_funcobj);
}
/* Unstable API functions */
PyObject *
PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)
{
PyObject *code = frame->f_executable;
Py_INCREF(code);
return code;
}
int
PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)
{
return _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
}
int
PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame)
{
int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
return PyCode_Addr2Line(_PyFrame_GetCode(frame), addr);
}
const PyTypeObject *const PyUnstable_ExecutableKinds[PyUnstable_EXECUTABLE_KINDS+1] = {
[PyUnstable_EXECUTABLE_KIND_SKIP] = &_PyNone_Type,
[PyUnstable_EXECUTABLE_KIND_PY_FUNCTION] = &PyCode_Type,
[PyUnstable_EXECUTABLE_KIND_BUILTIN_FUNCTION] = &PyMethod_Type,
[PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR] = &PyMethodDescr_Type,
[PyUnstable_EXECUTABLE_KINDS] = NULL,
};