diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2021-04-09 14:41:40 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2021-04-15 14:36:59 +0200 |
commit | 49c115b88d9175c7c160e81d11450c6d42029b5f (patch) | |
tree | 9c86a0906740d7397bdbd1d685b6185938445da1 /sources | |
parent | d47736aef4794c4eb81199d71f82ec1ebaced6cf (diff) |
shiboken6: Prevent crashes when registering static fields
Registering static fields invokes converters, which
can cause crashes for uninitialized types (see also
2ac1870053370e017567ae53e62cd1155a01c88f). To solve
this problem, move the static field initialization
to the end of the module initialization function
to ensure all converters are available.
Fixes: PYSIDE-1529
Change-Id: If40c6faf049077db8afcdee2069f4441c21beaa4
Reviewed-by: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
Reviewed-by: Christian Tismer <tismer@stackless.com>
(cherry picked from commit af1bdd8447771728321984f87447187f0284db6b)
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'sources')
4 files changed, 58 insertions, 12 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index 97bfd8f1b..06d5af14c 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -2116,6 +2116,12 @@ AbstractMetaField *AbstractMetaClass::findField(const QString &name) const return AbstractMetaField::find(m_fields, name); } +bool AbstractMetaClass::hasStaticFields() const +{ + return std::any_of(m_fields.cbegin(), m_fields.cend(), + [](const AbstractMetaField *f) { return f->isStatic(); }); +} + AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName) { if (AbstractMetaEnum *e = findByName(m_enums, enumName)) diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h index 52adebf94..9d0facd7d 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -1417,6 +1417,8 @@ public: AbstractMetaField *findField(const QString &name) const; + bool hasStaticFields() const; + const AbstractMetaEnumList &enums() const { return m_enums; } void setEnums(const AbstractMetaEnumList &enums) { diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 4f3bd2d0a..f299ba428 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -755,6 +755,9 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo writeConverterFunctions(s, metaClass, classContext); writeClassRegister(s, metaClass, classContext, signatureStream); + if (metaClass->hasStaticFields()) + writeStaticFieldInitialization(s, metaClass); + // class inject-code native/end if (!metaClass->typeEntry()->codeSnips().isEmpty()) { writeClassCodeSnips(s, metaClass->typeEntry()->codeSnips(), @@ -5274,6 +5277,12 @@ QString CppGenerator::getSimpleClassInitFunctionName(const AbstractMetaClass *me return initFunctionName; } +QString CppGenerator::getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass) const +{ + return QLatin1String("init_") + getSimpleClassInitFunctionName(metaClass) + + QLatin1String("StaticFields"); +} + QString CppGenerator::getInitFunctionName(const GeneratorContext &context) const { return !context.forSmartPointer() @@ -5476,18 +5485,6 @@ void CppGenerator::writeClassRegister(QTextStream &s, if (metaClass->hasSignals()) writeSignalInitialization(s, metaClass); - // Write static fields - const AbstractMetaFieldList &fields = metaClass->fields(); - for (const AbstractMetaField *field : fields) { - if (!field->isStatic()) - continue; - s << INDENT << QLatin1String("PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(") + cpythonTypeName(metaClass) + QLatin1String(")->tp_dict, \""); - s << field->name() << "\", "; - writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name()); - s << ");\n"; - } - s << Qt::endl; - // class inject-code target/end if (!classTypeEntry->codeSnips().isEmpty()) { s << Qt::endl; @@ -5517,6 +5514,29 @@ void CppGenerator::writeClassRegister(QTextStream &s, s << "}\n"; } +void CppGenerator::writeStaticFieldInitialization(QTextStream &s, + const AbstractMetaClass *metaClass) +{ + s << "\nvoid " << getSimpleClassStaticFieldsInitFunctionName(metaClass) + << "()\n{\n" << INDENT << "auto dict = reinterpret_cast<PyTypeObject *>(" + << cpythonTypeName(metaClass) << ")->tp_dict;\n"; + const auto &fields = metaClass->fields(); + for (const AbstractMetaField *field : fields) { + if (field->isStatic()) { + QString cppName = field->originalName(); + if (cppName.isEmpty()) + cppName = field->name(); + const QString name = field->enclosingClass()->qualifiedCppName() + + QLatin1String("::") + cppName; + s << INDENT << "PyDict_SetItemString(dict, \"" << field->name() + << "\",\n" << INDENT << " "; + writeToPythonConversion(s, field->type(), metaClass, name); + s << ");\n"; + } + } + s << "\n}\n"; +} + void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream &s, const GeneratorContext &context) const { const AbstractMetaClass *metaClass = context.metaClass(); @@ -5927,11 +5947,18 @@ bool CppGenerator::finishGeneration() } const AbstractMetaClassList lst = classesTopologicalSorted(additionalDependencies); + QVector<const AbstractMetaClass *> classesWithStaticFields; + for (const AbstractMetaClass *cls : lst){ if (shouldGenerate(cls)) { writeInitFunc(s_classInitDecl, s_classPythonDefines, INDENT, getSimpleClassInitFunctionName(cls), cls->typeEntry()->targetLangEnclosingEntry()); + if (cls->hasStaticFields()) { + s_classInitDecl << "void " + << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n"; + classesWithStaticFields.append(cls); + } } } @@ -6233,6 +6260,14 @@ bool CppGenerator::finishGeneration() s << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");\n"; s << INDENT << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");\n"; + // Static fields are registered last since they may use converter functions + // of the previously registered types (PYSIDE-1529). + if (!classesWithStaticFields.isEmpty()) { + s << "\n// Static field initialization\n"; + for (auto cls : qAsConst(classesWithStaticFields)) + s << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n"; + } + s << '\n' << INDENT << "if (PyErr_Occurred()) {\n" << indent(INDENT) << INDENT << "PyErr_Print();\n" << INDENT << "Py_FatalError(\"can't initialize module " << moduleName() << "\");\n" diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h index 79b8774a9..cc03c86e0 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.h +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h @@ -250,6 +250,7 @@ private: QString getInitFunctionName(const GeneratorContext &context) const; QString getSimpleClassInitFunctionName(const AbstractMetaClass *metaClass) const; + QString getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass) const; void writeSignatureStrings(QTextStream &s, QTextStream &signatureStream, const QString &arrayName, @@ -258,6 +259,8 @@ private: const AbstractMetaClass *metaClass, const GeneratorContext &classContext, QTextStream &signatureStream); + void writeStaticFieldInitialization(QTextStream &s, + const AbstractMetaClass *metaClass); void writeClassDefinition(QTextStream &s, const AbstractMetaClass *metaClass, const GeneratorContext &classContext); |