| https://github.com/protocolbuffers/protobuf/commit/2206b63c4649cf2e8a06b66c9191c8ef862ca519 |
| https://github.com/protocolbuffers/protobuf/pull/10403 |
| https://github.com/protocolbuffers/protobuf/issues/10305 |
| https://bugs.gentoo.org/844184 |
| |
| From da973aff2adab60a9e516d3202c111dbdde1a50f Mon Sep 17 00:00:00 2001 |
| From: Alexander Shadchin <alexandr.shadchin@gmail.com> |
| Date: Sun, 14 Aug 2022 21:13:49 +0300 |
| Subject: [PATCH] Fix build with Python 3.11 |
| |
| The PyFrameObject structure members have been removed from the public C API. |
| --- a/google/protobuf/pyext/descriptor.cc |
| +++ b/google/protobuf/pyext/descriptor.cc |
| @@ -58,6 +58,37 @@ |
| : 0) \ |
| : PyBytes_AsStringAndSize(ob, (charpp), (sizep))) |
| |
| +#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) |
| +static PyCodeObject* PyFrame_GetCode(PyFrameObject *frame) |
| +{ |
| + Py_INCREF(frame->f_code); |
| + return frame->f_code; |
| +} |
| + |
| +static PyFrameObject* PyFrame_GetBack(PyFrameObject *frame) |
| +{ |
| + Py_XINCREF(frame->f_back); |
| + return frame->f_back; |
| +} |
| +#endif |
| + |
| +#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION) |
| +static PyObject* PyFrame_GetLocals(PyFrameObject *frame) |
| +{ |
| + if (PyFrame_FastToLocalsWithError(frame) < 0) { |
| + return NULL; |
| + } |
| + Py_INCREF(frame->f_locals); |
| + return frame->f_locals; |
| +} |
| + |
| +static PyObject* PyFrame_GetGlobals(PyFrameObject *frame) |
| +{ |
| + Py_INCREF(frame->f_globals); |
| + return frame->f_globals; |
| +} |
| +#endif |
| + |
| namespace google { |
| namespace protobuf { |
| namespace python { |
| @@ -96,48 +127,66 @@ bool _CalledFromGeneratedFile(int stacklevel) { |
| // This check is not critical and is somewhat difficult to implement correctly |
| // in PyPy. |
| PyFrameObject* frame = PyEval_GetFrame(); |
| + PyCodeObject* frame_code = nullptr; |
| + PyObject* frame_globals = nullptr; |
| + PyObject* frame_locals = nullptr; |
| + bool result = false; |
| + |
| if (frame == nullptr) { |
| - return false; |
| + goto exit; |
| } |
| + Py_INCREF(frame); |
| while (stacklevel-- > 0) { |
| - frame = frame->f_back; |
| + PyFrameObject* next_frame = PyFrame_GetBack(frame); |
| + Py_DECREF(frame); |
| + frame = next_frame; |
| if (frame == nullptr) { |
| - return false; |
| + goto exit; |
| } |
| } |
| |
| - if (frame->f_code->co_filename == nullptr) { |
| - return false; |
| + frame_code = PyFrame_GetCode(frame); |
| + if (frame_code->co_filename == nullptr) { |
| + goto exit; |
| } |
| char* filename; |
| Py_ssize_t filename_size; |
| - if (PyString_AsStringAndSize(frame->f_code->co_filename, |
| + if (PyString_AsStringAndSize(frame_code->co_filename, |
| &filename, &filename_size) < 0) { |
| // filename is not a string. |
| PyErr_Clear(); |
| - return false; |
| + goto exit; |
| } |
| if ((filename_size < 3) || |
| (strcmp(&filename[filename_size - 3], ".py") != 0)) { |
| // Cython's stack does not have .py file name and is not at global module |
| // scope. |
| - return true; |
| + result = true; |
| + goto exit; |
| } |
| if (filename_size < 7) { |
| // filename is too short. |
| - return false; |
| + goto exit; |
| } |
| if (strcmp(&filename[filename_size - 7], "_pb2.py") != 0) { |
| // Filename is not ending with _pb2. |
| - return false; |
| + goto exit; |
| } |
| |
| - if (frame->f_globals != frame->f_locals) { |
| + frame_globals = PyFrame_GetGlobals(frame); |
| + frame_locals = PyFrame_GetLocals(frame); |
| + if (frame_globals != frame_locals) { |
| // Not at global module scope |
| - return false; |
| + goto exit; |
| } |
| #endif |
| - return true; |
| + result = true; |
| +exit: |
| + Py_XDECREF(frame_globals); |
| + Py_XDECREF(frame_locals); |
| + Py_XDECREF(frame_code); |
| + Py_XDECREF(frame); |
| + return result; |
| } |
| |
| // If the calling code is not a _pb2.py file, raise AttributeError. |
| |