diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-12-13 14:03:32 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2019-01-03 18:50:54 +0000 |
commit | e254c3c2aa140016e298107a0297885234abfde7 (patch) | |
tree | db15ce3a6329ec3cc87a1b53f91e62ce754aeadc /sources/shiboken2/generator/shiboken2/cppgenerator.cpp | |
parent | 0b352fca7391d01ce410ec0c04c285326e465dc1 (diff) |
Fix crash related to multiple inheritance
In the <class>_PTR_CppToPython_<class> 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 <class>_PTR_CppToPython_<class> 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 <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/shiboken2/generator/shiboken2/cppgenerator.cpp')
-rw-r--r-- | sources/shiboken2/generator/shiboken2/cppgenerator.cpp | 44 |
1 files changed, 40 insertions, 4 deletions
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<QString, QString> CppGenerator::m_sqFuncs = QHash<QString, QString>(); QHash<QString, QString> CppGenerator::m_mpFuncs = QHash<QString, QString>(); QString CppGenerator::m_currentErrorCode(QLatin1String("0")); +static const char typeNameFunc[] = R"CPP( +template <class T> +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 <cctype>\n#include <cstring>\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<void*>(cppIn), false, false, typeName);"; + c << INDENT << "bool changedTypeName = false;\n" + << INDENT << "auto tCppIn = reinterpret_cast<const " << typeName << " *>(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<void*>(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); |