]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-96237: Allow non-functions as reference-holder in frames. (GH-96238)
authorMark Shannon <mark@hotpy.org>
Thu, 25 Aug 2022 09:16:55 +0000 (10:16 +0100)
committerGitHub <noreply@github.com>
Thu, 25 Aug 2022 09:16:55 +0000 (10:16 +0100)
Include/internal/pycore_frame.h
Misc/NEWS.d/next/Core and Builtins/2022-08-24-14-30-26.gh-issue-96237.msif5f.rst [new file with mode: 0644]
Modules/_testinternalcapi.c
Objects/frameobject.c
Python/ceval.c
Python/frame.c

index 994c205c3d1644c6c555bf36d67352b88b742b65..decaafd141e9e1e301fe12099ae8a7e84350a2a5 100644 (file)
@@ -47,7 +47,7 @@ enum _frameowner {
 
 typedef struct _PyInterpreterFrame {
     /* "Specials" section */
-    PyFunctionObject *f_func; /* Strong reference */
+    PyObject *f_funcobj; /* Strong reference */
     PyObject *f_globals; /* Borrowed reference */
     PyObject *f_builtins; /* Borrowed reference */
     PyObject *f_locals; /* Strong reference, may be NULL */
@@ -101,7 +101,7 @@ _PyFrame_InitializeSpecials(
     _PyInterpreterFrame *frame, PyFunctionObject *func,
     PyObject *locals, PyCodeObject *code)
 {
-    frame->f_func = func;
+    frame->f_funcobj = (PyObject *)func;
     frame->f_code = (PyCodeObject *)Py_NewRef(code);
     frame->f_builtins = func->func_builtins;
     frame->f_globals = func->func_globals;
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-24-14-30-26.gh-issue-96237.msif5f.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-24-14-30-26.gh-issue-96237.msif5f.rst
new file mode 100644 (file)
index 0000000..cb8a1c0
--- /dev/null
@@ -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.
index 9d92b076387f6133aa2ad563cbfeeb1e7f17d3f8..02a061b84f85a3cb635c95da3b59e70997b9b5ae 100644 (file)
@@ -511,7 +511,9 @@ set_eval_frame_default(PyObject *self, PyObject *Py_UNUSED(args))
 static PyObject *
 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);
 }
 
index 26b38bae780c70e7ed8f6b03971aa234ae6c6f19..d2647bd122888cb3d6c81530d544defcd22a8763 100644 (file)
@@ -910,7 +910,7 @@ frame_dealloc(PyFrameObject *f)
         /* Don't clear code object until the end */
         co = frame->f_code;
         frame->f_code = NULL;
-        Py_CLEAR(frame->f_func);
+        Py_CLEAR(frame->f_funcobj);
         Py_CLEAR(frame->f_locals);
         PyObject **locals = _PyFrame_GetLocalsArray(frame);
         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
     // here:
     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 */
         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;
         for (int i = 0; i < co->co_nfreevars; ++i) {
             PyObject *o = PyTuple_GET_ITEM(closure, i);
index ac77ab8e8692fe0ffe1675f1ebe1fb47c19ad0b0..b3a0a3640eb97dfd3fc10323da56f8e4daa94feb 100644 (file)
@@ -154,11 +154,12 @@ lltrace_instruction(_PyInterpreterFrame *frame,
 static void
 lltrace_resume_frame(_PyInterpreterFrame *frame)
 {
-    PyFunctionObject *f = frame->f_func;
-    if (f == NULL) {
+    PyObject *fobj = frame->f_funcobj;
+    if (fobj == NULL || !PyFunction_Check(fobj)) {
         printf("\nResuming frame.");
         return;
     }
+    PyFunctionObject *f = (PyFunctionObject *)fobj;
     PyObject *type, *value, *traceback;
     PyErr_Fetch(&type, &value, &traceback);
     PyObject *name = f->func_qualname;
@@ -2619,7 +2620,8 @@ handle_eval_breaker:
         TARGET(COPY_FREE_VARS) {
             /* Copy closure variables to free variables */
             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;
             assert(oparg == co->co_nfreevars);
             for (int i = 0; i < oparg; ++i) {
@@ -4897,7 +4899,9 @@ handle_eval_breaker:
         }
 
         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) {
                 goto error;
             }
@@ -4919,7 +4923,7 @@ handle_eval_breaker:
             /* Make sure that frame is in a valid state */
             frame->stacktop = 0;
             frame->f_locals = NULL;
-            Py_INCREF(frame->f_func);
+            Py_INCREF(frame->f_funcobj);
             Py_INCREF(frame->f_code);
             /* Restore previous cframe and return. */
             tstate->cframe = cframe.previous;
index 7c6705e208f3d37a1db04a1affc874e0f6f903f2..14464df0a8d506270f7c301e108cb3b312790d88 100644 (file)
@@ -13,7 +13,7 @@ _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg)
 {
     Py_VISIT(frame->frame_obj);
     Py_VISIT(frame->f_locals);
-    Py_VISIT(frame->f_func);
+    Py_VISIT(frame->f_funcobj);
     Py_VISIT(frame->f_code);
    /* locals */
     PyObject **locals = _PyFrame_GetLocalsArray(frame);
@@ -114,7 +114,7 @@ _PyFrame_Clear(_PyInterpreterFrame *frame)
     }
     Py_XDECREF(frame->frame_obj);
     Py_XDECREF(frame->f_locals);
-    Py_DECREF(frame->f_func);
+    Py_DECREF(frame->f_funcobj);
     Py_DECREF(frame->f_code);
 }