diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 9f877ccda8..35c64180d4 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -69,11 +69,17 @@ static inline int metaDataSignatureLength() static QJsonDocument jsonFromCborMetaData(const char *raw, qsizetype size, QString *errMsg) { - if (Q_UNLIKELY(raw[-1] != '!')) { - *errMsg = QStringLiteral("Invalid metadata signature"); + // extract the keys not stored in CBOR + int qt_metadataVersion = quint8(raw[0]); + int qt_version = qFromBigEndian(raw + 1); + int qt_archRequirements = quint8(raw[3]); + if (Q_UNLIKELY(raw[-1] != '!' || qt_metadataVersion != 0)) { + *errMsg = QStringLiteral("Invalid metadata version"); return QJsonDocument(); } + raw += 4; + size -= 4; QByteArray ba = QByteArray::fromRawData(raw, int(size)); QCborParserError err; QCborValue metadata = QCborValue::fromCbor(ba, &err); @@ -88,8 +94,12 @@ static QJsonDocument jsonFromCborMetaData(const char *raw, qsizetype size, QStri return QJsonDocument(); } - // convert the top-level map integer keys QJsonObject o; + o.insert(QLatin1String("version"), qt_version << 8); + o.insert(QLatin1String("debug"), bool(qt_archRequirements & 1)); + o.insert(QLatin1String("archreq"), qt_archRequirements); + + // convert the top-level map integer keys for (auto it : metadata.toMap()) { QString key; if (it.first.isInteger()) { @@ -98,6 +108,12 @@ static QJsonDocument jsonFromCborMetaData(const char *raw, qsizetype size, QStri case int(IntKey): key = QStringLiteral(StringKey); break; QT_PLUGIN_FOREACH_METADATA(CONVERT_TO_STRING) #undef CONVERT_TO_STRING + + case int(QtPluginMetaDataKeys::Requirements): + // special case: recreate the debug key + o.insert(QLatin1String("debug"), bool(it.second.toInteger() & 1)); + key = QStringLiteral("archreq"); + break; } } else { key = it.first.toString(); diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h index 9922026f97..5aca22497a 100644 --- a/src/corelib/plugin/qplugin.h +++ b/src/corelib/plugin/qplugin.h @@ -55,6 +55,21 @@ QT_BEGIN_NAMESPACE # endif #endif +inline constexpr unsigned char qPluginArchRequirements() +{ + return 0 +#ifndef QT_NO_DEBUG + | 1 +#endif +#ifdef __AVX2__ + | 2 +# ifdef __AVX512F__ + | 4 +# endif +#endif + ; +} + typedef QObject *(*QtPluginInstanceFunction)(); typedef const char *(*QtPluginMetaDataFunction)(); diff --git a/src/corelib/plugin/qplugin_p.h b/src/corelib/plugin/qplugin_p.h index 99ee16a3e8..717129268b 100644 --- a/src/corelib/plugin/qplugin_p.h +++ b/src/corelib/plugin/qplugin_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE enum class QtPluginMetaDataKeys { QtVersion, - Debug, + Requirements, IID, ClassName, MetaData @@ -66,8 +66,6 @@ enum class QtPluginMetaDataKeys { // F(IntKey, StringKey, Description) // Keep this list sorted in the order moc should output. #define QT_PLUGIN_FOREACH_METADATA(F) \ - F(QtPluginMetaDataKeys::QtVersion, "version", "Qt version built against") \ - F(QtPluginMetaDataKeys::Debug, "debug", "Whether it is a debug build") \ F(QtPluginMetaDataKeys::IID, "IID", "Plugin's Interface ID") \ F(QtPluginMetaDataKeys::ClassName, "className", "Plugin class name") \ F(QtPluginMetaDataKeys::MetaData, "MetaData", "Other meta data") diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index e5154b779b..e499d22618 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1624,8 +1624,11 @@ void Generator::generatePluginMetaData() return; fputs("\nQT_PLUGIN_METADATA_SECTION\n" - "static const unsigned char qt_pluginMetaData[] = {\n" - " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',", out); + "static constexpr unsigned char qt_pluginMetaData[] = {\n" + " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',\n" + " // metadata version, Qt version, architectural requirements\n" + " 0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),", out); + CborDevice dev(out); CborEncoder enc; @@ -1634,20 +1637,6 @@ void Generator::generatePluginMetaData() CborEncoder map; cbor_encoder_create_map(&enc, &map, CborIndefiniteLength); - dev.nextItem("\"version\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::QtVersion)); - cbor_encode_int(&map, QT_VERSION); - - fputs("\n#ifdef QT_NO_DEBUG", out); - dev.nextItem("\"debug\" = false"); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::Debug)); - cbor_encode_boolean(&map, false); - fputs("\n#else", out); - dev.nextItem("\"debug\" = true"); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::Debug)); - cbor_encode_boolean(&map, true); - fputs("\n#endif", out); - dev.nextItem("\"IID\""); cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID)); cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size()); diff --git a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp index 8a5c325041..a290c012df 100644 --- a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp +++ b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -147,49 +148,62 @@ void tst_QPlugin::scanInvalidPlugin_data() QTest::newRow("json-control") << (prefix + QJsonDocument(obj).toBinaryData()) << true << ""; } - QTest::newRow("json-zeroes") << prefix << false << ""; + QTest::newRow("json-zeroes") << prefix << false << " "; prefix += "qbjs"; - QTest::newRow("bad-json-version0") << prefix << false << ""; - QTest::newRow("bad-json-version2") << (prefix + QByteArray("\2\0\0\0", 4)) << false << ""; + QTest::newRow("bad-json-version0") << prefix << false << " "; + QTest::newRow("bad-json-version2") << (prefix + QByteArray("\2\0\0\0", 4)) << false << " "; // valid qbjs version 1 prefix += QByteArray("\1\0\0\0"); // too large for the file (100 MB) - QTest::newRow("bad-json-size-large1") << (prefix + QByteArray("\0\0\x40\x06")) << false << ""; + QTest::newRow("bad-json-size-large1") << (prefix + QByteArray("\0\0\x40\x06")) << false << " "; // too large for binary JSON (512 MB) - QTest::newRow("bad-json-size-large2") << (prefix + QByteArray("\0\0\0\x20")) << false << ""; + QTest::newRow("bad-json-size-large2") << (prefix + QByteArray("\0\0\0\x20")) << false << " "; // could overflow - QTest::newRow("bad-json-size-large3") << (prefix + "\xff\xff\xff\x7f") << false << ""; + QTest::newRow("bad-json-size-large3") << (prefix + "\xff\xff\xff\x7f") << false << " "; #endif // CBOR metadata - QByteArray cprefix = "QTMETADATA !"; + QByteArray cprefix = "QTMETADATA !1234"; + cprefix[12] = 0; // current version + cprefix[13] = QT_VERSION_MAJOR; + cprefix[14] = QT_VERSION_MINOR; + cprefix[15] = qPluginArchRequirements(); - { + QByteArray cborValid = [] { QCborMap m; m.insert(int(QtPluginMetaDataKeys::IID), QLatin1String("org.qt-project.tst_qplugin")); m.insert(int(QtPluginMetaDataKeys::ClassName), QLatin1String("tst")); - m.insert(int(QtPluginMetaDataKeys::QtVersion), int(QT_VERSION)); -#ifdef QT_NO_DEBUG - m.insert(int(QtPluginMetaDataKeys::Debug), false); -#else - m.insert(int(QtPluginMetaDataKeys::Debug), true); -#endif m.insert(int(QtPluginMetaDataKeys::MetaData), QCborMap()); + return QCborValue(m).toCbor(); + }(); + QTest::newRow("cbor-control") << (cprefix + cborValid) << true << ""; - QTest::newRow("cbor-control") << (cprefix + QCborValue(m).toCbor()) << true << ""; - } + cprefix[12] = 1; + QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false + << " Invalid metadata version"; + + cprefix[12] = 0; + cprefix[13] = QT_VERSION_MAJOR + 1; + QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false << ""; + + cprefix[13] = QT_VERSION_MAJOR - 1; + QTest::newRow("cbor-major-too-old") << (cprefix + cborValid) << false << ""; + + cprefix[13] = QT_VERSION_MAJOR; + cprefix[14] = QT_VERSION_MINOR + 1; + QTest::newRow("cbor-minor-too-new") << (cprefix + cborValid) << false << ""; QTest::newRow("cbor-invalid") << (cprefix + "\xff") << false - << "Metadata parsing error: Invalid CBOR stream: unexpected 'break' byte"; + << " Metadata parsing error: Invalid CBOR stream: unexpected 'break' byte"; QTest::newRow("cbor-not-map1") << (cprefix + "\x01") << false - << "Unexpected metadata contents"; + << " Unexpected metadata contents"; QTest::newRow("cbor-not-map2") << (cprefix + "\x81\x01") << false - << "Unexpected metadata contents"; + << " Unexpected metadata contents"; } static const char invalidPluginSignature[] = "qplugin testfile"; @@ -246,10 +260,10 @@ void tst_QPlugin::scanInvalidPlugin() // now try to load this QFETCH(bool, loads); QFETCH(QString, errMsg); - if (!loads) + if (!errMsg.isEmpty()) QTest::ignoreMessage(QtWarningMsg, "Found invalid metadata in lib " + QFile::encodeName(newName) + - ": " + errMsg.toUtf8()); + ":" + errMsg.toUtf8()); QPluginLoader loader(newName); QCOMPARE(loader.load(), loads); if (loads)