QLibrary: fix loading multiple versions of a library
The libraryMap only stored the file path, so we couldn't load two versions of the same library as we'd find the other version already loaded. Change the map to index by file name and version (using a NUL as separator, since that can't appear in file names). [ChangeLog][QtCore][QLibrary] Fixed a bug that caused QLibrary to be unable to load two different versions of a library of a given name at the same time. Note that this is often inadviseable and loading the second library may cause a crash. Pick-to: 6.4 Change-Id: I12a088d1ae424825abd3fffd171ce3bb0590978d Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
3731e04668
commit
77eef32917
@ -391,10 +391,12 @@ inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, con
|
||||
QMutexLocker locker(&qt_library_mutex);
|
||||
QLibraryStore *data = instance();
|
||||
|
||||
QString mapName = version.isEmpty() ? fileName : fileName + u'\0' + version;
|
||||
|
||||
// check if this library is already loaded
|
||||
QLibraryPrivate *lib = nullptr;
|
||||
if (Q_LIKELY(data)) {
|
||||
lib = data->libraryMap.value(fileName);
|
||||
lib = data->libraryMap.value(mapName);
|
||||
if (lib)
|
||||
lib->mergeLoadHints(loadHints);
|
||||
}
|
||||
@ -403,7 +405,7 @@ inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, con
|
||||
|
||||
// track this library
|
||||
if (Q_LIKELY(data) && !fileName.isEmpty())
|
||||
data->libraryMap.insert(fileName, lib);
|
||||
data->libraryMap.insert(mapName, lib);
|
||||
|
||||
lib->libraryRefCount.ref();
|
||||
return lib;
|
||||
@ -423,9 +425,11 @@ inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib)
|
||||
Q_ASSERT(lib->libraryUnloadCount.loadRelaxed() == 0);
|
||||
|
||||
if (Q_LIKELY(data) && !lib->fileName.isEmpty()) {
|
||||
QLibraryPrivate *that = data->libraryMap.take(lib->fileName);
|
||||
Q_ASSERT(lib == that);
|
||||
Q_UNUSED(that);
|
||||
qsizetype n = erase_if(data->libraryMap, [lib](LibraryMap::iterator it) {
|
||||
return it.value() == lib;
|
||||
});
|
||||
Q_ASSERT_X(n, "~QLibrary", "Did not find this library in the library map");
|
||||
Q_UNUSED(n);
|
||||
}
|
||||
delete lib;
|
||||
}
|
||||
|
@ -96,6 +96,8 @@ private slots:
|
||||
void isLibrary();
|
||||
void version_data();
|
||||
void version();
|
||||
void loadTwoVersions();
|
||||
void setFileNameAndVersionTwice();
|
||||
void setFileNameAndVersionAfterFailedLoad_data() { version_data(); }
|
||||
void setFileNameAndVersionAfterFailedLoad();
|
||||
void errorString_data();
|
||||
@ -196,6 +198,70 @@ void tst_QLibrary::version()
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QLibrary::loadTwoVersions()
|
||||
{
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_WIN)
|
||||
QSKIP("Versioned files are not generated for this OS, so this test is not applicable.");
|
||||
#endif
|
||||
|
||||
QLibrary lib1(directory + "/mylib", 1);
|
||||
QLibrary lib2(directory + "/mylib", 2);
|
||||
QVERIFY(!lib1.isLoaded());
|
||||
QVERIFY(!lib2.isLoaded());
|
||||
|
||||
// load the first one
|
||||
QVERIFY(lib1.load());
|
||||
QVERIFY(lib1.isLoaded());
|
||||
|
||||
// let's see if we can load the second one too
|
||||
QVERIFY(lib2.load());
|
||||
QVERIFY(lib2.isLoaded());
|
||||
|
||||
auto p1 = (VersionFunction)lib1.resolve("mylibversion");
|
||||
QVERIFY(p1);
|
||||
|
||||
auto p2 = (VersionFunction)lib2.resolve("mylibversion");
|
||||
QVERIFY(p2);
|
||||
|
||||
QCOMPARE_NE(p1(), p2());
|
||||
|
||||
lib2.unload();
|
||||
lib1.unload();
|
||||
}
|
||||
|
||||
void tst_QLibrary::setFileNameAndVersionTwice()
|
||||
{
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_WIN)
|
||||
QSKIP("Versioned files are not generated for this OS, so this test is not applicable.");
|
||||
#endif
|
||||
|
||||
QLibrary library(directory + "/mylib", 1);
|
||||
QVERIFY(library.load());
|
||||
QVERIFY(library.isLoaded());
|
||||
|
||||
auto p1 = (VersionFunction)library.resolve("mylibversion");
|
||||
QVERIFY(p1);
|
||||
// don't .unload()
|
||||
|
||||
library.setFileNameAndVersion(directory + "/mylib", 2);
|
||||
QVERIFY(!library.isLoaded());
|
||||
QVERIFY(library.load());
|
||||
QVERIFY(library.isLoaded());
|
||||
|
||||
auto p2 = (VersionFunction)library.resolve("mylibversion");
|
||||
QVERIFY(p2);
|
||||
QCOMPARE_NE(p1(), p2());
|
||||
|
||||
QVERIFY(library.unload());
|
||||
QVERIFY(!library.isLoaded());
|
||||
|
||||
// set back
|
||||
library.setFileNameAndVersion(directory + "/mylib", 1);
|
||||
QVERIFY(library.isLoaded());
|
||||
QVERIFY(library.unload());
|
||||
QVERIFY(!library.isLoaded());
|
||||
}
|
||||
|
||||
void tst_QLibrary::load_data()
|
||||
{
|
||||
QTest::addColumn<QString>("lib");
|
||||
|
Loading…
Reference in New Issue
Block a user