diff options
Diffstat (limited to 'src/corelib/plugin')
-rw-r--r-- | src/corelib/plugin/plugin.pri | 1 | ||||
-rw-r--r-- | src/corelib/plugin/qfactoryloader.cpp | 127 | ||||
-rw-r--r-- | src/corelib/plugin/qfactoryloader_p.h | 3 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary.cpp | 48 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary_unix.cpp | 27 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary_win.cpp | 4 | ||||
-rw-r--r-- | src/corelib/plugin/qplugin.h | 28 | ||||
-rw-r--r-- | src/corelib/plugin/qplugin_p.h | 75 | ||||
-rw-r--r-- | src/corelib/plugin/qpluginloader.cpp | 11 | ||||
-rw-r--r-- | src/corelib/plugin/qsystemlibrary.cpp | 2 |
10 files changed, 267 insertions, 59 deletions
diff --git a/src/corelib/plugin/plugin.pri b/src/corelib/plugin/plugin.pri index a0e0d76044..13153e8d0a 100644 --- a/src/corelib/plugin/plugin.pri +++ b/src/corelib/plugin/plugin.pri @@ -4,6 +4,7 @@ HEADERS += \ plugin/qfactoryinterface.h \ plugin/qpluginloader.h \ plugin/qplugin.h \ + plugin/qplugin_p.h \ plugin/quuid.h \ plugin/qfactoryloader_p.h diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index dc1424fd0c..35c64180d4 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -47,9 +47,12 @@ #include <qdebug.h> #include "qmutex.h" #include "qplugin.h" +#include "qplugin_p.h" #include "qpluginloader.h" #include "private/qobject_p.h" #include "private/qcoreapplication_p.h" +#include "qcbormap.h" +#include "qcborvalue.h" #include "qjsondocument.h" #include "qjsonvalue.h" #include "qjsonobject.h" @@ -64,22 +67,86 @@ static inline int metaDataSignatureLength() return sizeof("QTMETADATA ") - 1; } -QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype sectionSize) +static QJsonDocument jsonFromCborMetaData(const char *raw, qsizetype size, QString *errMsg) +{ + // extract the keys not stored in CBOR + int qt_metadataVersion = quint8(raw[0]); + int qt_version = qFromBigEndian<quint16>(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); + + if (err.error != QCborError::NoError) { + *errMsg = QLatin1String("Metadata parsing error: ") + err.error.toString(); + return QJsonDocument(); + } + + if (!metadata.isMap()) { + *errMsg = QStringLiteral("Unexpected metadata contents"); + return QJsonDocument(); + } + + 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()) { + switch (it.first.toInteger()) { +#define CONVERT_TO_STRING(IntKey, StringKey, Description) \ + 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(); + } + + if (!key.isEmpty()) + o.insert(key, it.second.toJsonValue()); + } + return QJsonDocument(o); +} + +QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype sectionSize, QString *errMsg) { raw += metaDataSignatureLength(); sectionSize -= metaDataSignatureLength(); - // the size of the embedded JSON object can be found 8 bytes into the data (see qjson_p.h) - uint size = qFromLittleEndian<uint>(raw + 8); - // but the maximum size of binary JSON is 128 MB - size = qMin(size, 128U * 1024 * 1024); - // and it doesn't include the size of the header (8 bytes) - size += 8; - // finally, it can't be bigger than the file or section size - size = qMin(sectionSize, qsizetype(size)); - - QByteArray json(raw, size); - return QJsonDocument::fromBinaryData(json); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + if (Q_UNLIKELY(raw[-1] == ' ')) { + // the size of the embedded JSON object can be found 8 bytes into the data (see qjson_p.h) + uint size = qFromLittleEndian<uint>(raw + 8); + // but the maximum size of binary JSON is 128 MB + size = qMin(size, 128U * 1024 * 1024); + // and it doesn't include the size of the header (8 bytes) + size += 8; + // finally, it can't be bigger than the file or section size + size = qMin(sectionSize, qsizetype(size)); + + QByteArray json(raw, size); + return QJsonDocument::fromBinaryData(json); + } +#endif + + return jsonFromCborMetaData(raw, sectionSize, errMsg); } class QFactoryLoaderPrivate : public QObjectPrivate @@ -141,35 +208,33 @@ void QFactoryLoader::update() QDir::Files); QLibraryPrivate *library = 0; -#ifdef Q_OS_MAC - // Loading both the debug and release version of the cocoa plugins causes the objective-c runtime - // to print "duplicate class definitions" warnings. Detect if QFactoryLoader is about to load both, - // skip one of them (below). - // - // ### FIXME find a proper solution - // - const bool isLoadingDebugAndReleaseCocoa = plugins.contains(QLatin1String("libqcocoa_debug.dylib")) - && plugins.contains(QLatin1String("libqcocoa.dylib")); -#endif for (int j = 0; j < plugins.count(); ++j) { QString fileName = QDir::cleanPath(path + QLatin1Char('/') + plugins.at(j)); #ifdef Q_OS_MAC - if (isLoadingDebugAndReleaseCocoa) { -#ifdef QT_DEBUG - if (fileName.contains(QLatin1String("libqcocoa.dylib"))) - continue; // Skip release plugin in debug mode -#else - if (fileName.contains(QLatin1String("libqcocoa_debug.dylib"))) - continue; // Skip debug plugin in release mode -#endif + const bool isDebugPlugin = fileName.endsWith(QLatin1String("_debug.dylib")); + const bool isDebugLibrary = + #ifdef QT_DEBUG + true; + #else + false; + #endif + + // Skip mismatching plugins so that we don't end up loading both debug and release + // versions of the same Qt libraries (due to the plugin's dependencies). + if (isDebugPlugin != isDebugLibrary) + continue; +#elif defined(Q_PROCESSOR_X86) + if (fileName.endsWith(QLatin1String(".avx2")) || fileName.endsWith(QLatin1String(".avx512"))) { + // ignore AVX2-optimized file, we'll do a bait-and-switch to it later + continue; } #endif if (qt_debug_component()) { qDebug() << "QFactoryLoader::QFactoryLoader() looking at" << fileName; } - Q_TRACE(qfactoryloader_update, fileName); + Q_TRACE(QFactoryLoader_update, fileName); library = QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath()); if (!library->isPlugin()) { diff --git a/src/corelib/plugin/qfactoryloader_p.h b/src/corelib/plugin/qfactoryloader_p.h index fe722999ae..7815ea0b5d 100644 --- a/src/corelib/plugin/qfactoryloader_p.h +++ b/src/corelib/plugin/qfactoryloader_p.h @@ -56,6 +56,7 @@ #include "QtCore/qobject.h" #include "QtCore/qstringlist.h" +#include "QtCore/qcborvalue.h" #include "QtCore/qjsonobject.h" #include "QtCore/qjsondocument.h" #include "QtCore/qmap.h" @@ -66,7 +67,7 @@ QT_BEGIN_NAMESPACE -QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype size); +QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype size, QString *errMsg); class QFactoryLoaderPrivate; class Q_CORE_EXPORT QFactoryLoader : public QObject diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 5256a09ff2..aa63ed1a6b 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -268,7 +268,7 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) */ bool hasMetaData = false; qsizetype pos = 0; - char pattern[] = "qTMETADATA "; + char pattern[] = "qTMETADATA "; pattern[0] = 'Q'; // Ensure the pattern "QTMETADATA" is not found in this library should QPluginLoader ever encounter it. const ulong plen = qstrlen(pattern); #if defined (Q_OF_ELF) && defined(Q_CC_GNU) @@ -314,10 +314,14 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) bool ret = false; - if (pos >= 0) { - if (hasMetaData) { - const char *data = filedata + pos; - QJsonDocument doc = qJsonFromRawLibraryMetaData(data, qsizetype(fdlen)); + if (pos >= 0 && hasMetaData) { + const char *data = filedata + pos; + QString errMsg; + QJsonDocument doc = qJsonFromRawLibraryMetaData(data, fdlen, &errMsg); + if (doc.isNull()) { + qWarning("Found invalid metadata in lib %s: %s", + qPrintable(library), qPrintable(errMsg)); + } else { lib->metaData = doc.object(); if (qt_debug_component()) qWarning("Found metadata in lib %s, metadata=\n%s\n", @@ -544,7 +548,7 @@ bool QLibraryPrivate::load() if (fileName.isEmpty()) return false; - Q_TRACE(qlibraryprivate_load_entry, fileName); + Q_TRACE(QLibraryPrivate_load_entry, fileName); bool ret = load_sys(); if (qt_debug_component()) { @@ -562,7 +566,7 @@ bool QLibraryPrivate::load() installCoverageTool(this); } - Q_TRACE(qlibraryprivate_load_exit, ret); + Q_TRACE(QLibraryPrivate_load_exit, ret); return ret; } @@ -679,20 +683,26 @@ bool QLibrary::isLibrary(const QString &fileName) #endif } -typedef const char * (*QtPluginQueryVerificationDataFunction)(); - -static bool qt_get_metadata(QtPluginQueryVerificationDataFunction pfn, QLibraryPrivate *priv) +static bool qt_get_metadata(QLibraryPrivate *priv, QString *errMsg) { - const char *szData = 0; - if (!pfn) - return false; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + auto getMetaData = [](QFunctionPointer fptr) { + auto f = reinterpret_cast<const char * (*)()>(fptr); + return qMakePair<const char *, size_t>(f(), INT_MAX); + }; +#else + auto getMetaData = [](QFunctionPointer fptr) { + auto f = reinterpret_cast<QPair<const char *, size_t> (*)()>(fptr); + return f(); + }; +#endif - szData = pfn(); - if (!szData) + QFunctionPointer pfn = priv->resolve("qt_plugin_query_metadata"); + if (!pfn) return false; - // the data is already loaded, so the size doesn't matter - QJsonDocument doc = qJsonFromRawLibraryMetaData(szData, INT_MAX); + auto metaData = getMetaData(pfn); + QJsonDocument doc = qJsonFromRawLibraryMetaData(metaData.first, metaData.second, errMsg); if (doc.isNull()) return false; priv->metaData = doc.object(); @@ -735,9 +745,7 @@ void QLibraryPrivate::updatePluginState() } else { // library is already loaded (probably via QLibrary) // simply get the target function and call it. - QtPluginQueryVerificationDataFunction getMetaData = NULL; - getMetaData = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_metadata"); - success = qt_get_metadata(getMetaData, this); + success = qt_get_metadata(this, &errorString); } if (!success) { diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 23b9ad6434..e03814984c 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 Intel Corporation ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -43,6 +44,7 @@ #include "qlibrary_p.h" #include <qcoreapplication.h> #include <private/qfilesystementry_p.h> +#include <private/qsimd_p.h> #include <dlfcn.h> @@ -155,7 +157,7 @@ bool QLibraryPrivate::load_sys() // Do not unload the library during dlclose(). Consequently, the // library's specific static variables are not reinitialized if the // library is reloaded with dlopen() at a later time. -#ifdef RTLD_NODELETE +#if defined(RTLD_NODELETE) && !defined(Q_OS_ANDROID) if (loadHints & QLibrary::PreventUnloadHint) { dlFlags |= RTLD_NODELETE; } @@ -178,6 +180,29 @@ bool QLibraryPrivate::load_sys() prefixes.append(QString()); } +#if defined(Q_PROCESSOR_X86) && !defined(Q_OS_DARWIN) + if (qCpuHasFeature(ArchHaswell)) { + auto transform = [](QStringList &list, void (*f)(QString *)) { + QStringList tmp; + qSwap(tmp, list); + list.reserve(tmp.size() * 2); + for (const QString &s : qAsConst(tmp)) { + QString modifiedPath = s; + f(&modifiedPath); + list.append(modifiedPath); + list.append(s); + } + }; + if (pluginState == IsAPlugin) { + // add ".avx2" to each suffix in the list + transform(suffixes, [](QString *s) { s->append(QLatin1String(".avx2")); }); + } else { + // prepend "haswell/" to each prefix in the list + transform(prefixes, [](QString *s) { s->prepend(QLatin1String("haswell/")); }); + } + } +#endif + bool retry = true; for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) { for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) { diff --git a/src/corelib/plugin/qlibrary_win.cpp b/src/corelib/plugin/qlibrary_win.cpp index 9368e53b3f..05a93d467e 100644 --- a/src/corelib/plugin/qlibrary_win.cpp +++ b/src/corelib/plugin/qlibrary_win.cpp @@ -97,10 +97,10 @@ bool QLibraryPrivate::load_sys() for (const QString &attempt : qAsConst(attempts)) { #ifndef Q_OS_WINRT - pHnd = LoadLibrary((wchar_t*)QDir::toNativeSeparators(attempt).utf16()); + pHnd = LoadLibrary(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(attempt).utf16())); #else // Q_OS_WINRT QString path = QDir::toNativeSeparators(QDir::current().relativeFilePath(attempt)); - pHnd = LoadPackagedLibrary((LPCWSTR)path.utf16(), 0); + pHnd = LoadPackagedLibrary(reinterpret_cast<LPCWSTR>(path.utf16()), 0); if (pHnd) qualifiedFileName = attempt; #endif // !Q_OS_WINRT diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h index b644d47856..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)(); @@ -90,7 +105,6 @@ void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin staticPlugin); # define QT_PLUGIN_METADATA_SECTION \ __declspec(allocate(".qtmetadata")) #else -# define QT_PLUGIN_VERIFICATION_SECTION # define QT_PLUGIN_METADATA_SECTION #endif @@ -105,11 +119,21 @@ void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin staticPlugin); }; \ static Static##PLUGIN##PluginInstance static##PLUGIN##Instance; +#if defined(QT_PLUGIN_RESOURCE_INIT_FUNCTION) +# define QT_PLUGIN_RESOURCE_INIT \ + extern void QT_PLUGIN_RESOURCE_INIT_FUNCTION(); \ + QT_PLUGIN_RESOURCE_INIT_FUNCTION(); +#else +# define QT_PLUGIN_RESOURCE_INIT +#endif + #define Q_PLUGIN_INSTANCE(IMPLEMENTATION) \ { \ static QT_PREPEND_NAMESPACE(QPointer)<QT_PREPEND_NAMESPACE(QObject)> _instance; \ - if (!_instance) \ + if (!_instance) { \ + QT_PLUGIN_RESOURCE_INIT \ _instance = new IMPLEMENTATION; \ + } \ return _instance; \ } diff --git a/src/corelib/plugin/qplugin_p.h b/src/corelib/plugin/qplugin_p.h new file mode 100644 index 0000000000..717129268b --- /dev/null +++ b/src/corelib/plugin/qplugin_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Intel Corporation. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPLUGIN_P_H +#define QPLUGIN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qglobal_p.h> + +QT_BEGIN_NAMESPACE + +enum class QtPluginMetaDataKeys { + QtVersion, + Requirements, + IID, + ClassName, + MetaData +}; + +// F(IntKey, StringKey, Description) +// Keep this list sorted in the order moc should output. +#define QT_PLUGIN_FOREACH_METADATA(F) \ + F(QtPluginMetaDataKeys::IID, "IID", "Plugin's Interface ID") \ + F(QtPluginMetaDataKeys::ClassName, "className", "Plugin class name") \ + F(QtPluginMetaDataKeys::MetaData, "MetaData", "Other meta data") + +QT_END_NAMESPACE + +#endif // QPLUGIN_P_H diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp index 83cbcd2b44..0f94bb6adf 100644 --- a/src/corelib/plugin/qpluginloader.cpp +++ b/src/corelib/plugin/qpluginloader.cpp @@ -475,10 +475,19 @@ QVector<QStaticPlugin> QPluginLoader::staticPlugins() */ QJsonObject QStaticPlugin::metaData() const { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // the data is already loaded, so this doesn't matter qsizetype rawMetaDataSize = INT_MAX; + const char *ptr = rawMetaData(); +#else + auto ptr = static_cast<const char *>(rawMetaData); +#endif - return qJsonFromRawLibraryMetaData(rawMetaData(), rawMetaDataSize).object(); + QString errMsg; + QJsonDocument doc = qJsonFromRawLibraryMetaData(ptr, rawMetaDataSize, &errMsg); + Q_ASSERT(doc.isObject()); + Q_ASSERT(errMsg.isEmpty()); + return doc.object(); } QT_END_NAMESPACE diff --git a/src/corelib/plugin/qsystemlibrary.cpp b/src/corelib/plugin/qsystemlibrary.cpp index 7c80fbbd42..1f8cef790c 100644 --- a/src/corelib/plugin/qsystemlibrary.cpp +++ b/src/corelib/plugin/qsystemlibrary.cpp @@ -121,7 +121,7 @@ HINSTANCE QSystemLibrary::load(const wchar_t *libraryName, bool onlySystemDirect fullPathAttempt.append(QLatin1Char('\\')); } fullPathAttempt.append(fileName); - HINSTANCE inst = ::LoadLibrary((const wchar_t *)fullPathAttempt.utf16()); + HINSTANCE inst = ::LoadLibrary(reinterpret_cast<const wchar_t *>(fullPathAttempt.utf16())); if (inst != 0) return inst; } |