From a1b78213b3d0d8cdda373fc710772ab8e93a836b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 10 Jan 2025 18:36:51 -0300 Subject: [PATCH] QFactoryLoader: unload the plugins we loaded MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We just left everything for QLibraryStore::cleanup() to do when that ran at QtCore unload time. Which is certainly weird because that meant no other library could be unloaded if it was a dependency of a plugin we'd loaded. Now, this should allow the libraries to start unloading before QtCore, when the Q_GLOBAL_STATICs holding the QFactoryLoaders get destroyed by ::exit(). This also explicitly deletes the instances in each of those dynamic plugins, otherwise they may remain around and cause crashes later. This is not done for instances coming from staticplugins - see next commit. Change-Id: I752d41069e192c7be4a0fffd5ab0a253108b0b0c Reviewed-by: Fabian Kosmale Reviewed-by: Tor Arne Vestbø --- src/corelib/plugin/qfactoryloader.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index c1c4812044c..a7ce5994213 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -261,6 +261,7 @@ public: ~QFactoryLoaderPrivate(); QDuplicateTracker loadedPaths; std::vector libraries; + mutable QList loadedLibraries; std::map keyMap; QString suffix; QString extraSearchPath; @@ -391,6 +392,8 @@ inline void QFactoryLoaderPrivate::updateSinglePath(const QString &path) libraries.push_back(std::move(library)); } }; + + loadedLibraries.resize(libraries.size()); } void QFactoryLoader::update() @@ -419,10 +422,22 @@ void QFactoryLoader::update() QFactoryLoader::~QFactoryLoader() { + Q_D(QFactoryLoader); + if (!qt_factoryloader_global.isDestroyed()) { QMutexLocker locker(&qt_factoryloader_global->mutex); qt_factoryloader_global->loaders.removeOne(this); } + +#if QT_CONFIG(library) + for (qsizetype i = 0; i < d->loadedLibraries.size(); ++i) { + if (d->loadedLibraries.at(i)) { + auto &plugin = d->libraries.at(i); + delete plugin->inst.data(); + plugin->unload(); + } + } +#endif } #if defined(Q_OS_UNIX) && !defined (Q_OS_DARWIN) @@ -489,6 +504,13 @@ void QFactoryLoader::setExtraSearchPath(const QString &path) d->updateSinglePath(d->extraSearchPath); } else { // must re-scan everything + for (qsizetype i = 0; i < d->loadedLibraries.size(); ++i) { + if (d->loadedLibraries.at(i)) { + auto &plugin = d->libraries.at(i); + delete plugin->inst.data(); + } + } + d->loadedLibraries.fill(false); d->loadedPaths.clear(); d->libraries.clear(); d->keyMap.clear(); @@ -573,6 +595,7 @@ inline QObject *QFactoryLoader::instanceHelper_locked(int index) const #if QT_CONFIG(library) if (size_t(index) < d->libraries.size()) { QLibraryPrivate *library = d->libraries[index].get(); + d->loadedLibraries[index] = true; return library->pluginInstance(); } // we know d->libraries.size() <= index <= numeric_limits::max() → no overflow