summaryrefslogtreecommitdiffstats
path: root/src/corelib/plugin/qlibrary.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2019-12-18 18:45:36 -0800
committerThiago Macieira <thiago.macieira@intel.com>2020-03-03 14:36:32 -0800
commitae6f73e8566fa76470937aca737141183929a5ec (patch)
tree4a45798d9c4d6b1e5f163a4d215ce4988e76d1bc /src/corelib/plugin/qlibrary.cpp
parentef92ac5636c2f0407fba8141c35ea61d391fd479 (diff)
QLibrary: introduce a mutex to protect non-atomic internals
And make pHnd atomic. The majority of the variables is updated in QLibraryPrivate::load_sys and updatePluginState(), which get the mutex protection. QLibraryPrivate::unload_sys() doesn't need a mutex protection because we have the refcounting. [ChangeLog][QtCore][QLibrary & QPluginLoader] Fixed a number of race conditions caused by having two QLibrary objects pointing to the same library being operated in different threads. Fixes: QTBUG-39642 Change-Id: I46bf1f65e8db46afbde5fffd15e1a5b3f5e74ea4 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib/plugin/qlibrary.cpp')
-rw-r--r--src/corelib/plugin/qlibrary.cpp42
1 files changed, 27 insertions, 15 deletions
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp
index 7ce959cc8f..ddb053c26f 100644
--- a/src/corelib/plugin/qlibrary.cpp
+++ b/src/corelib/plugin/qlibrary.cpp
@@ -407,7 +407,7 @@ inline void QLibraryStore::cleanup()
QLibraryPrivate *lib = it.value();
if (lib->libraryRefCount.loadRelaxed() == 1) {
if (lib->libraryUnloadCount.loadRelaxed() > 0) {
- Q_ASSERT(lib->pHnd);
+ Q_ASSERT(lib->pHnd.loadRelaxed());
lib->libraryUnloadCount.storeRelaxed(1);
#ifdef __GLIBC__
// glibc has a bug in unloading from global destructors
@@ -498,8 +498,7 @@ inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib)
}
QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints)
- : pHnd(0), fileName(canonicalFileName), fullVersion(version),
- libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin)
+ : fileName(canonicalFileName), fullVersion(version), pluginState(MightBeAPlugin)
{
loadHintsInt.storeRelaxed(loadHints);
if (canonicalFileName.isEmpty())
@@ -519,7 +518,7 @@ QLibraryPrivate::~QLibraryPrivate()
void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
{
// if the library is already loaded, we can't change the load hints
- if (pHnd)
+ if (pHnd.loadRelaxed())
return;
loadHintsInt.storeRelaxed(lh);
@@ -527,7 +526,7 @@ void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
{
- if (!pHnd)
+ if (!pHnd.loadRelaxed())
return 0;
return resolve_sys(symbol);
}
@@ -542,7 +541,7 @@ void QLibraryPrivate::setLoadHints(QLibrary::LoadHints lh)
QObject *QLibraryPrivate::pluginInstance()
{
// first, check if the instance is cached and hasn't been deleted
- QObject *obj = inst.data();
+ QObject *obj = (QMutexLocker(&mutex), inst.data());
if (obj)
return obj;
@@ -558,6 +557,7 @@ QObject *QLibraryPrivate::pluginInstance()
obj = factory();
// cache again
+ QMutexLocker locker(&mutex);
if (inst)
obj = inst;
else
@@ -567,7 +567,7 @@ QObject *QLibraryPrivate::pluginInstance()
bool QLibraryPrivate::load()
{
- if (pHnd) {
+ if (pHnd.loadRelaxed()) {
libraryUnloadCount.ref();
return true;
}
@@ -576,7 +576,9 @@ bool QLibraryPrivate::load()
Q_TRACE(QLibraryPrivate_load_entry, fileName);
+ mutex.lock();
bool ret = load_sys();
+ mutex.unlock();
if (qt_debug_component()) {
if (ret) {
qDebug() << "loaded library" << fileName;
@@ -599,9 +601,10 @@ bool QLibraryPrivate::load()
bool QLibraryPrivate::unload(UnloadFlag flag)
{
- if (!pHnd)
+ if (!pHnd.loadRelaxed())
return false;
if (libraryUnloadCount.loadRelaxed() > 0 && !libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
+ QMutexLocker locker(&mutex);
delete inst.data();
if (flag == NoUnloadSys || unload_sys()) {
if (qt_debug_component())
@@ -610,12 +613,13 @@ bool QLibraryPrivate::unload(UnloadFlag flag)
//when the library is unloaded, we release the reference on it so that 'this'
//can get deleted
libraryRefCount.deref();
- pHnd = 0;
+ pHnd.storeRelaxed(nullptr);
instanceFactory.storeRelaxed(nullptr);
+ return true;
}
}
- return (pHnd == 0);
+ return false;
}
void QLibraryPrivate::release()
@@ -746,6 +750,7 @@ bool QLibraryPrivate::isPlugin()
void QLibraryPrivate::updatePluginState()
{
+ QMutexLocker locker(&mutex);
errorString.clear();
if (pluginState != MightBeAPlugin)
return;
@@ -766,7 +771,7 @@ void QLibraryPrivate::updatePluginState()
}
#endif
- if (!pHnd) {
+ if (!pHnd.loadRelaxed()) {
// scan for the plugin metadata without loading
success = findPatternUnloaded(fileName, this);
} else {
@@ -830,7 +835,7 @@ bool QLibrary::load()
if (!d)
return false;
if (did_load)
- return d->pHnd;
+ return d->pHnd.loadRelaxed();
did_load = true;
return d->load();
}
@@ -866,7 +871,7 @@ bool QLibrary::unload()
*/
bool QLibrary::isLoaded() const
{
- return d && d->pHnd;
+ return d && d->pHnd.loadRelaxed();
}
@@ -977,8 +982,10 @@ void QLibrary::setFileName(const QString &fileName)
QString QLibrary::fileName() const
{
- if (d)
+ if (d) {
+ QMutexLocker locker(&d->mutex);
return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName;
+ }
return QString();
}
@@ -1119,7 +1126,12 @@ QFunctionPointer QLibrary::resolve(const QString &fileName, const QString &versi
*/
QString QLibrary::errorString() const
{
- return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString;
+ QString str;
+ if (d) {
+ QMutexLocker locker(&d->mutex);
+ str = d->errorString;
+ }
+ return str.isEmpty() ? tr("Unknown error") : str;
}
/*!