aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2019-08-30 06:27:49 +0200
committerSimo Fält <simo.falt@qt.io>2019-09-06 09:17:41 +0000
commit0add41759ad3346a8ea93863e347e73e98700bec (patch)
tree28229db285686b6d6624b2dde01740b04ec2a8a1 /sources
parent91003e1e355e0cfc8a152d527d29c2599e022a6a (diff)
Fix heaptype conflict with QtCore.QObject.__new__in Python 2.7
The patching of the type generation needs to become universal. Additional to the patch for SbkObjectType_TypeF, we now patch * SbkObjectTypeTpNew * introduceWrapperType which makes the modifications for the heaptype flag complete. Actually, the modification of tp_new_wrapper has to be more sophisticated in this general case: We follow the __mro__ and patch exactly those functions which have the old wrapper and add the new wrapper. Change-Id: I51d4d77c99bd18eed2e31d2ab21143c0f4e2ea6c Fixes: PYSIDE-1051 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io> (cherry picked from commit cd6172063756a59e02f1a7857bc60a1737214ad1)
Diffstat (limited to 'sources')
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp94
1 files changed, 54 insertions, 40 deletions
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index b9f6735d8..9d233b847 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -92,6 +92,7 @@ static PyType_Slot SbkObjectType_Type_slots[] = {
{Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)},
{Py_tp_new, reinterpret_cast<void *>(SbkObjectTypeTpNew)},
{Py_tp_free, reinterpret_cast<void *>(PyObject_GC_Del)},
+ {Py_tp_getset, reinterpret_cast<void *>(SbkObjectType_Type_getsetlist)},
{0, nullptr}
};
static PyType_Spec SbkObjectType_Type_spec = {
@@ -106,7 +107,7 @@ static PyType_Spec SbkObjectType_Type_spec = {
#if PY_VERSION_HEX < 0x03000000
/*****************************************************************************
*
- * PYSIDE-816: Workaround for Python 2.7
+ * PYSIDE-816: Workaround for Python 2.7 for SbkObjectType_TypeF().
*
* This is an add-on for function typeobject.c:tp_new_wrapper from Python 2.7 .
* Problem:
@@ -121,9 +122,16 @@ static PyType_Spec SbkObjectType_Type_spec = {
* The problem is that heap types have this unwanted dependency.
* But we cannot get at static slot_tp_new, and so we have to use
* the original function and patch Py_TPFLAGS_HEAPTYPE away during the call.
+ *
+ * PYSIDE-1051: The same problem holds for all dynamic metatypes generated by
+ * SbkObjectTypeTpNew() and all types generated by
+ * introduceWrapperType() .
+ *
+ * This led to a drastic overhaul of patch_tp_new_wrapper() which now adds
+ * the new wrapper to exactly those types which have the old wrapper.
*/
-static PyCFunction old_tp_new_wrapper = nullptr;
+ternaryfunc old_tp_new_wrapper = nullptr;
static PyObject *
tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
@@ -136,9 +144,9 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
return ret;
}
-// This is intentionally the new docstring of Python 3.7 .
+// This is intentionally the __new__ docstring of Python 3.7 .
static struct PyMethodDef tp_new_methoddef[] = {
- {"__new__", (PyCFunction)tp_new_wrapper, METH_VARARGS|METH_KEYWORDS,
+ {"__new__", reinterpret_cast<PyCFunction>(tp_new_wrapper), METH_VARARGS|METH_KEYWORDS,
PyDoc_STR("__new__($type, *args, **kwargs)\n--\n\n"
"Create and return a new object. "
"See help(type) for accurate signature.")},
@@ -146,43 +154,39 @@ static struct PyMethodDef tp_new_methoddef[] = {
};
static int
-get_old_tp_new_wrapper(void)
-{
- // We get the old tp_new_wrapper from any initialized type.
- PyTypeObject *type = &PyType_Type;
- PyObject *dict = type->tp_dict;
- PyObject *key, *func = nullptr;
- Py_ssize_t pos = 0;
- while (PyDict_Next(dict, &pos, &key, &func)) {
- char *name = PyString_AsString(key);
- if (strcmp(name, "__new__") == 0) {
- break;
+patch_tp_new_wrapper(PyTypeObject *type)
+{
+ /*
+ * The old tp_new_wrapper is added to all types that have tp_new.
+ * We patch that with a version that ignores the heaptype flag.
+ */
+ static PyObject *__new__ = nullptr;
+ if (old_tp_new_wrapper == nullptr) {
+ if ((__new__ = Py_BuildValue("s", "__new__")) == nullptr)
+ return -1;
+ PyObject *func = PyDict_GetItem(PyType_Type.tp_dict, __new__);
+ PyCFunctionObject *pycf_ob = reinterpret_cast<PyCFunctionObject *>(func);
+ old_tp_new_wrapper = reinterpret_cast<ternaryfunc>(pycf_ob->m_ml->ml_meth);
+ }
+ PyObject *mro = type->tp_mro;
+ Py_ssize_t i, n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i));
+ PyObject *existing = PyDict_GetItem(type->tp_dict, __new__);
+ if (existing && PyCFunction_Check(existing)
+ && type->tp_flags & Py_TPFLAGS_HEAPTYPE) {
+ auto *pycf_ob = reinterpret_cast<PyCFunctionObject *>(existing);
+ auto existing_wrapper = reinterpret_cast<ternaryfunc>(pycf_ob->m_ml->ml_meth);
+ if (existing_wrapper == tp_new_wrapper)
+ break;
+ if (existing_wrapper == old_tp_new_wrapper) {
+ PyObject *ob_type = reinterpret_cast<PyObject *>(type);
+ Shiboken::AutoDecRef func(PyCFunction_New(tp_new_methoddef, ob_type));
+ if (func.isNull() || PyDict_SetItem(type->tp_dict, __new__, func))
+ return -1;
+ }
}
}
- if (func == nullptr)
- return -1;
- PyCFunctionObject *pycf_ob = reinterpret_cast<PyCFunctionObject *>(func);
- old_tp_new_wrapper = pycf_ob->m_ml->ml_meth;
- return 0;
-}
-
-static int
-add_tp_new_wrapper(PyTypeObject *type)
-{
- // get the original tp_new_wrapper
- if (old_tp_new_wrapper == nullptr && get_old_tp_new_wrapper() < 0)
- return -1;
- // initialize tp_dict
- if (type->tp_dict == nullptr)
- type->tp_dict = PyDict_New();
- if (type->tp_dict == nullptr)
- return -1;
- PyObject *ob_type = reinterpret_cast<PyObject *>(type);
- Shiboken::AutoDecRef func(PyCFunction_New(tp_new_methoddef, ob_type));
- if (func.isNull())
- return -1;
- if (PyDict_SetItemString(type->tp_dict, "__new__", func))
- return -1;
return 0;
}
/*****************************************************************************/
@@ -197,7 +201,7 @@ PyTypeObject *SbkObjectType_TypeF(void)
PepHeapType_SIZE + sizeof(SbkObjectTypePrivate);
type = reinterpret_cast<PyTypeObject *>(PyType_FromSpec(&SbkObjectType_Type_spec));
#if PY_VERSION_HEX < 0x03000000
- if (add_tp_new_wrapper(type) < 0)
+ if (patch_tp_new_wrapper(type) < 0)
return nullptr;
#endif
}
@@ -452,6 +456,11 @@ PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *k
auto *newType = reinterpret_cast<SbkObjectType *>(type_new(metatype, args, kwds));
if (!newType)
return nullptr;
+#if PY_VERSION_HEX < 0x03000000
+ // PYSIDE-1051: The newly created metatype needs the PYSIDE-816 wrapper, too.
+ if (patch_tp_new_wrapper(&newType->type) < 0)
+ return nullptr;
+#endif
Shiboken::ObjectType::initPrivateData(newType);
SbkObjectTypePrivate *sotp = PepType_SOTP(newType);
@@ -842,6 +851,11 @@ introduceWrapperType(PyObject *enclosingObject,
Py_TYPE(heaptype) = SbkObjectType_TypeF();
Py_INCREF(Py_TYPE(heaptype));
auto *type = reinterpret_cast<SbkObjectType *>(heaptype);
+#if PY_VERSION_HEX < 0x03000000
+ // PYSIDE-1051: The newly created type needs the PYSIDE-816 wrapper, too.
+ if (patch_tp_new_wrapper(&type->type) < 0)
+ return nullptr;
+#endif
if (baseType) {
if (baseTypes) {
for (int i = 0; i < PySequence_Fast_GET_SIZE(baseTypes); ++i)