GH-96237: Allow non-functions as reference-holder in frames. (GH-96238)

This commit is contained in:
Mark Shannon 2022-08-25 10:16:55 +01:00 committed by GitHub
parent 8db7693bbf
commit c09fa7542c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 26 additions and 13 deletions

View file

@ -47,7 +47,7 @@ enum _frameowner {
typedef struct _PyInterpreterFrame { typedef struct _PyInterpreterFrame {
/* "Specials" section */ /* "Specials" section */
PyFunctionObject *f_func; /* Strong reference */ PyObject *f_funcobj; /* Strong reference */
PyObject *f_globals; /* Borrowed reference */ PyObject *f_globals; /* Borrowed reference */
PyObject *f_builtins; /* Borrowed reference */ PyObject *f_builtins; /* Borrowed reference */
PyObject *f_locals; /* Strong reference, may be NULL */ PyObject *f_locals; /* Strong reference, may be NULL */
@ -101,7 +101,7 @@ _PyFrame_InitializeSpecials(
_PyInterpreterFrame *frame, PyFunctionObject *func, _PyInterpreterFrame *frame, PyFunctionObject *func,
PyObject *locals, PyCodeObject *code) PyObject *locals, PyCodeObject *code)
{ {
frame->f_func = func; frame->f_funcobj = (PyObject *)func;
frame->f_code = (PyCodeObject *)Py_NewRef(code); frame->f_code = (PyCodeObject *)Py_NewRef(code);
frame->f_builtins = func->func_builtins; frame->f_builtins = func->func_builtins;
frame->f_globals = func->func_globals; frame->f_globals = func->func_globals;

View file

@ -0,0 +1,5 @@
The internal field ``_PyInterpreterFrame.f_func`` is renamed to
``_PyInterpreterFrame.f_funcobj`` and may be any object. The ``f_globals``
and ``f_builtin`` fields may hold junk values.
It is safest to treat the ``_PyInterpreterFrame`` struct as opaque.

View file

@ -511,7 +511,9 @@ set_eval_frame_default(PyObject *self, PyObject *Py_UNUSED(args))
static PyObject * static PyObject *
record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc) record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc)
{ {
PyList_Append(record_list, f->f_func->func_name); if (PyFunction_Check(f->f_funcobj)) {
PyList_Append(record_list, ((PyFunctionObject *)f->f_funcobj)->func_name);
}
return _PyEval_EvalFrameDefault(tstate, f, exc); return _PyEval_EvalFrameDefault(tstate, f, exc);
} }

View file

@ -910,7 +910,7 @@ frame_dealloc(PyFrameObject *f)
/* Don't clear code object until the end */ /* Don't clear code object until the end */
co = frame->f_code; co = frame->f_code;
frame->f_code = NULL; frame->f_code = NULL;
Py_CLEAR(frame->f_func); Py_CLEAR(frame->f_funcobj);
Py_CLEAR(frame->f_locals); Py_CLEAR(frame->f_locals);
PyObject **locals = _PyFrame_GetLocalsArray(frame); PyObject **locals = _PyFrame_GetLocalsArray(frame);
for (int i = 0; i < frame->stacktop; i++) { for (int i = 0; i < frame->stacktop; i++) {
@ -1154,10 +1154,12 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) {
// COPY_FREE_VARS has no quickened forms, so no need to use _PyOpcode_Deopt // COPY_FREE_VARS has no quickened forms, so no need to use _PyOpcode_Deopt
// here: // here:
int lasti = _PyInterpreterFrame_LASTI(frame); int lasti = _PyInterpreterFrame_LASTI(frame);
if (lasti < 0 && _Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS) { if (lasti < 0 && _Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS
&& PyFunction_Check(frame->f_funcobj))
{
/* Free vars have not been initialized -- Do that */ /* Free vars have not been initialized -- Do that */
PyCodeObject *co = frame->f_code; PyCodeObject *co = frame->f_code;
PyObject *closure = frame->f_func->func_closure; PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
int offset = co->co_nlocals + co->co_nplaincellvars; int offset = co->co_nlocals + co->co_nplaincellvars;
for (int i = 0; i < co->co_nfreevars; ++i) { for (int i = 0; i < co->co_nfreevars; ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i); PyObject *o = PyTuple_GET_ITEM(closure, i);

View file

@ -154,11 +154,12 @@ lltrace_instruction(_PyInterpreterFrame *frame,
static void static void
lltrace_resume_frame(_PyInterpreterFrame *frame) lltrace_resume_frame(_PyInterpreterFrame *frame)
{ {
PyFunctionObject *f = frame->f_func; PyObject *fobj = frame->f_funcobj;
if (f == NULL) { if (fobj == NULL || !PyFunction_Check(fobj)) {
printf("\nResuming frame."); printf("\nResuming frame.");
return; return;
} }
PyFunctionObject *f = (PyFunctionObject *)fobj;
PyObject *type, *value, *traceback; PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback); PyErr_Fetch(&type, &value, &traceback);
PyObject *name = f->func_qualname; PyObject *name = f->func_qualname;
@ -2619,7 +2620,8 @@ handle_eval_breaker:
TARGET(COPY_FREE_VARS) { TARGET(COPY_FREE_VARS) {
/* Copy closure variables to free variables */ /* Copy closure variables to free variables */
PyCodeObject *co = frame->f_code; PyCodeObject *co = frame->f_code;
PyObject *closure = frame->f_func->func_closure; assert(PyFunction_Check(frame->f_funcobj));
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
int offset = co->co_nlocals + co->co_nplaincellvars; int offset = co->co_nlocals + co->co_nplaincellvars;
assert(oparg == co->co_nfreevars); assert(oparg == co->co_nfreevars);
for (int i = 0; i < oparg; ++i) { for (int i = 0; i < oparg; ++i) {
@ -4897,7 +4899,9 @@ handle_eval_breaker:
} }
TARGET(RETURN_GENERATOR) { TARGET(RETURN_GENERATOR) {
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(frame->f_func); assert(PyFunction_Check(frame->f_funcobj));
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
if (gen == NULL) { if (gen == NULL) {
goto error; goto error;
} }
@ -4919,7 +4923,7 @@ handle_eval_breaker:
/* Make sure that frame is in a valid state */ /* Make sure that frame is in a valid state */
frame->stacktop = 0; frame->stacktop = 0;
frame->f_locals = NULL; frame->f_locals = NULL;
Py_INCREF(frame->f_func); Py_INCREF(frame->f_funcobj);
Py_INCREF(frame->f_code); Py_INCREF(frame->f_code);
/* Restore previous cframe and return. */ /* Restore previous cframe and return. */
tstate->cframe = cframe.previous; tstate->cframe = cframe.previous;

View file

@ -13,7 +13,7 @@ _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg)
{ {
Py_VISIT(frame->frame_obj); Py_VISIT(frame->frame_obj);
Py_VISIT(frame->f_locals); Py_VISIT(frame->f_locals);
Py_VISIT(frame->f_func); Py_VISIT(frame->f_funcobj);
Py_VISIT(frame->f_code); Py_VISIT(frame->f_code);
/* locals */ /* locals */
PyObject **locals = _PyFrame_GetLocalsArray(frame); PyObject **locals = _PyFrame_GetLocalsArray(frame);
@ -114,7 +114,7 @@ _PyFrame_Clear(_PyInterpreterFrame *frame)
} }
Py_XDECREF(frame->frame_obj); Py_XDECREF(frame->frame_obj);
Py_XDECREF(frame->f_locals); Py_XDECREF(frame->f_locals);
Py_DECREF(frame->f_func); Py_DECREF(frame->f_funcobj);
Py_DECREF(frame->f_code); Py_DECREF(frame->f_code);
} }