1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
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.
---
python/google/protobuf/pyext/descriptor.cc | 75 ++++++++++++++++++----
1 file changed, 62 insertions(+), 13 deletions(-)
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index fc83acf01a..fc97b0fa6c 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/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.
|