From e254c3c2aa140016e298107a0297885234abfde7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 13 Dec 2018 14:03:32 +0100 Subject: Fix crash related to multiple inheritance In the _PTR_CppToPython_ converter function (written by CppGenerator::writeConverterFunctions()), the generated code used typeid(*ptr).name() to retrieve the name to use for the SbkObjectTypes. This construct returns the name of the outermost class (for example, "QWidget" for a QWidget-type paint device returned by QPainter::device()), as opposed to "QPaintDevice *" returned by typeid(ptr).name(). This caused a crash with multiple inheritance since QWidget inherits QObject and QPaintDevice and the "QWidget" type was associated with the QPaintDevice pointer. To fix this: - Add API to libshiboken to obtain the SbkObjectType* by name and check for the presence of a special cast function (multiple inheritance). - Generate the code of _PTR_CppToPython_ as follows: Check whether the outermost type obtained by typeid(*ptr).name() has a special cast function. If that is the case, use the type name obtained by typeid(ptr).name() (base class) to create the wrapper. Change-Id: I8ee6b4c084e9dafa434623433661809b83aedee5 Fixes: PYSIDE-868 Reviewed-by: Cristian Maureira-Fredes --- .../shiboken2/generator/shiboken2/cppgenerator.cpp | 44 ++++++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) (limited to 'sources/shiboken2/generator/shiboken2/cppgenerator.cpp') diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index e46e0b968..9df0d61c5 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -50,6 +50,30 @@ QHash CppGenerator::m_sqFuncs = QHash(); QHash CppGenerator::m_mpFuncs = QHash(); QString CppGenerator::m_currentErrorCode(QLatin1String("0")); +static const char typeNameFunc[] = R"CPP( +template +static const char *typeNameOf(const T &t) +{ + const char *typeName = typeid(t).name(); + auto size = std::strlen(typeName); +#if defined(Q_CC_MSVC) // MSVC: "class QPaintDevice * __ptr64" + if (auto lastStar = strchr(typeName, '*')) { + // MSVC: "class QPaintDevice * __ptr64" + while (*--lastStar == ' ') { + } + size = lastStar - typeName + 1; + } +#else // g++, Clang: "QPaintDevice *" -> "P12QPaintDevice" + if (size > 2 && typeName[0] == 'P' && std::isdigit(typeName[1])) + ++typeName; +#endif + char *result = new char[size + 1]; + result[size] = '\0'; + strncpy(result, typeName, size); + return result; +} +)CPP"; + // utility functions inline AbstractMetaType* getTypeWithoutContainer(AbstractMetaType* arg) { @@ -336,6 +360,8 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) s << inc.toString() << endl; s << endl; + s << "\n#include \n#include \n"; + if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated) s << "#Deprecated" << endl; @@ -351,7 +377,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) } } - s << endl; + s << endl << endl << typeNameFunc << endl; // Create string literal for smart pointer getter method. if (classContext.forSmartPointer()) { @@ -1226,9 +1252,19 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla c << INDENT << "return pyOut;" << endl; } c << INDENT << '}' << endl; - c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl; - c << INDENT << "return Shiboken::Object::newObject(" << cpythonType; - c << ", const_cast(cppIn), false, false, typeName);"; + c << INDENT << "bool changedTypeName = false;\n" + << INDENT << "auto tCppIn = reinterpret_cast(cppIn);\n" + << INDENT << "const char *typeName = typeid(*tCppIn).name();\n" + << INDENT << "auto sbkType = Shiboken::ObjectType::typeForTypeName(typeName);\n" + << INDENT << "if (sbkType && Shiboken::ObjectType::hasSpecialCastFunction(sbkType)) {\n" + << INDENT << " typeName = typeNameOf(tCppIn);\n" + << INDENT << " changedTypeName = true;\n" + << INDENT << " }\n" + << INDENT << "PyObject *result = Shiboken::Object::newObject(" << cpythonType + << ", const_cast(cppIn), false, /* exactType */ changedTypeName, typeName);\n" + << INDENT << "if (changedTypeName)\n" + << INDENT << " delete [] typeName;\n" + << INDENT << "return result;"; } std::swap(targetTypeName, sourceTypeName); writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); -- cgit v1.2.3