QPluginLoader: don't instantiante multiple, identical instances
This can happen if the same project has two or more Q_IMPORT_PLUGIN macros in their source. And that can happen when converting from qmake- based builds to CMake, as qmake didn't generate a source file with the macro but CMake does. [ChangeLog][QtCore][QPluginLoader] staticInstances() will not call duplicated registrations of the same instantiation function, which can only happen as a result of duplicated Q_IMPORT_PLUGIN for the same plugin name. Fixes: QTBUG-102745 Pick-to: 6.2 6.5 Change-Id: Idd5e1bb52be047d7b4fffffd174fb9dd62d8583d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>bb10
parent
a74059f2bd
commit
2f226336a2
|
|
@ -379,7 +379,19 @@ Q_GLOBAL_STATIC(StaticPluginList, staticPluginList)
|
|||
*/
|
||||
void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin plugin)
|
||||
{
|
||||
staticPluginList()->append(plugin);
|
||||
// using operator* because we shouldn't be registering plugins while
|
||||
// unloading the application!
|
||||
StaticPluginList &plugins = *staticPluginList;
|
||||
|
||||
// insert the plugin in the list, sorted by address, so we can detect
|
||||
// duplicate registrations
|
||||
auto comparator = [=](const QStaticPlugin &p1, const QStaticPlugin &p2) {
|
||||
using Less = std::less<decltype(plugin.instance)>;
|
||||
return Less{}(p1.instance, p2.instance);
|
||||
};
|
||||
auto pos = std::lower_bound(plugins.constBegin(), plugins.constEnd(), plugin, comparator);
|
||||
if (pos == plugins.constEnd() || pos->instance != plugin.instance)
|
||||
plugins.insert(pos, plugin);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ private slots:
|
|||
void preloadedPlugin_data();
|
||||
void preloadedPlugin();
|
||||
void staticPlugins();
|
||||
void reregisteredStaticPlugins();
|
||||
};
|
||||
|
||||
Q_IMPORT_PLUGIN(StaticPlugin)
|
||||
|
|
@ -1080,19 +1081,18 @@ void tst_QPluginLoader::staticPlugins()
|
|||
const QObjectList instances = QPluginLoader::staticInstances();
|
||||
QVERIFY(instances.size());
|
||||
|
||||
bool found = false;
|
||||
for (QObject *obj : instances) {
|
||||
found = obj->metaObject()->className() == QLatin1String("StaticPlugin");
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
QVERIFY(found);
|
||||
// ensure the our plugin only shows up once
|
||||
int foundCount = std::count_if(instances.begin(), instances.end(), [](QObject *obj) {
|
||||
return obj->metaObject()->className() == QLatin1String("StaticPlugin");
|
||||
});
|
||||
QCOMPARE(foundCount, 1);
|
||||
|
||||
const auto plugins = QPluginLoader::staticPlugins();
|
||||
QCOMPARE(plugins.size(), instances.size());
|
||||
|
||||
// find the metadata
|
||||
QJsonObject metaData;
|
||||
bool found = false;
|
||||
for (const auto &p : plugins) {
|
||||
metaData = p.metaData();
|
||||
found = metaData.value("className").toString() == QLatin1String("StaticPlugin");
|
||||
|
|
@ -1108,6 +1108,18 @@ void tst_QPluginLoader::staticPlugins()
|
|||
QCOMPARE(metaData.value("URI").toString(), "qt.test.pluginloader.staticplugin");
|
||||
}
|
||||
|
||||
void tst_QPluginLoader::reregisteredStaticPlugins()
|
||||
{
|
||||
// the Q_IMPORT_PLUGIN macro will have already done this
|
||||
qRegisterStaticPluginFunction(qt_static_plugin_StaticPlugin());
|
||||
staticPlugins();
|
||||
if (QTest::currentTestFailed())
|
||||
return;
|
||||
|
||||
qRegisterStaticPluginFunction(qt_static_plugin_StaticPlugin());
|
||||
staticPlugins();
|
||||
}
|
||||
|
||||
|
||||
QTEST_MAIN(tst_QPluginLoader)
|
||||
#include "tst_qpluginloader.moc"
|
||||
|
|
|
|||
Loading…
Reference in New Issue