Fix a few more race conditions with QLibrary::LoadHints

This commit makes replaces the loadHints member with a setter, a getter
and an atomic variable. The setter will not set anything if the library
has already been loaded.

Task-number: QTBUG-39642
Change-Id: Ibb7692f16d80211b52aaf4dc88db1a989738a24d
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Thiago Macieira 2014-07-21 16:36:24 -07:00
parent 800d0076e0
commit cfaf851e26
5 changed files with 40 additions and 22 deletions

View File

@ -485,9 +485,9 @@ inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib)
QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints) QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints)
: pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0), : pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0),
loadHints(loadHints),
libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin) libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin)
{ {
loadHintsInt.store(loadHints);
if (canonicalFileName.isEmpty()) if (canonicalFileName.isEmpty())
errorString = QLibrary::tr("The shared library was not found."); errorString = QLibrary::tr("The shared library was not found.");
} }
@ -508,7 +508,7 @@ void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
if (pHnd) if (pHnd)
return; return;
loadHints = lh; loadHintsInt.store(lh);
} }
QFunctionPointer QLibraryPrivate::resolve(const char *symbol) QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
@ -518,6 +518,12 @@ QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
return resolve_sys(symbol); return resolve_sys(symbol);
} }
void QLibraryPrivate::setLoadHints(QLibrary::LoadHints lh)
{
// this locks a global mutex
QMutexLocker lock(&qt_library_mutex);
mergeLoadHints(lh);
}
bool QLibraryPrivate::load() bool QLibraryPrivate::load()
{ {
@ -914,13 +920,12 @@ void QLibrary::setFileName(const QString &fileName)
{ {
QLibrary::LoadHints lh; QLibrary::LoadHints lh;
if (d) { if (d) {
lh = d->loadHints; lh = d->loadHints();
d->release(); d->release();
d = 0; d = 0;
did_load = false; did_load = false;
} }
d = QLibraryPrivate::findOrCreate(fileName); d = QLibraryPrivate::findOrCreate(fileName, QString(), lh);
d->loadHints = lh;
} }
QString QLibrary::fileName() const QString QLibrary::fileName() const
@ -943,13 +948,12 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum)
{ {
QLibrary::LoadHints lh; QLibrary::LoadHints lh;
if (d) { if (d) {
lh = d->loadHints; lh = d->loadHints();
d->release(); d->release();
d = 0; d = 0;
did_load = false; did_load = false;
} }
d = QLibraryPrivate::findOrCreate(fileName, verNum >= 0 ? QString::number(verNum) : QString()); d = QLibraryPrivate::findOrCreate(fileName, verNum >= 0 ? QString::number(verNum) : QString(), lh);
d->loadHints = lh;
} }
/*! /*!
@ -965,13 +969,12 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver
{ {
QLibrary::LoadHints lh; QLibrary::LoadHints lh;
if (d) { if (d) {
lh = d->loadHints; lh = d->loadHints();
d->release(); d->release();
d = 0; d = 0;
did_load = false; did_load = false;
} }
d = QLibraryPrivate::findOrCreate(fileName, version); d = QLibraryPrivate::findOrCreate(fileName, version, lh);
d->loadHints = lh;
} }
/*! /*!
@ -1102,6 +1105,12 @@ QString QLibrary::errorString() const
By default, none of these flags are set, so libraries will be loaded with By default, none of these flags are set, so libraries will be loaded with
lazy symbol resolution, and will not export external symbols for resolution lazy symbol resolution, and will not export external symbols for resolution
in other dynamically-loaded libraries. in other dynamically-loaded libraries.
\note Setting this property after the library has been loaded has no effect
and loadHints() will not reflect those changes.
\note This property is shared among all QLibrary instances that refer to
the same library.
*/ */
void QLibrary::setLoadHints(LoadHints hints) void QLibrary::setLoadHints(LoadHints hints)
{ {
@ -1109,12 +1118,12 @@ void QLibrary::setLoadHints(LoadHints hints)
d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
d->errorString.clear(); d->errorString.clear();
} }
d->loadHints = hints; d->setLoadHints(hints);
} }
QLibrary::LoadHints QLibrary::loadHints() const QLibrary::LoadHints QLibrary::loadHints() const
{ {
return d ? d->loadHints : (QLibrary::LoadHints)0; return d ? d->loadHints() : QLibrary::LoadHints();
} }
/* Internal, for debugging */ /* Internal, for debugging */

View File

@ -94,6 +94,10 @@ public:
void release(); void release();
QFunctionPointer resolve(const char *); QFunctionPointer resolve(const char *);
QLibrary::LoadHints loadHints() const
{ return QLibrary::LoadHints(loadHintsInt.load()); }
void setLoadHints(QLibrary::LoadHints lh);
static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString(), static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString(),
QLibrary::LoadHints loadHints = 0); QLibrary::LoadHints loadHints = 0);
static QStringList suffixes_sys(const QString &fullVersion); static QStringList suffixes_sys(const QString &fullVersion);
@ -104,7 +108,6 @@ public:
QJsonObject metaData; QJsonObject metaData;
QString errorString; QString errorString;
QLibrary::LoadHints loadHints;
void updatePluginState(); void updatePluginState();
bool isPlugin(); bool isPlugin();
@ -126,6 +129,8 @@ private:
bool unload_sys(); bool unload_sys();
QFunctionPointer resolve_sys(const char *); QFunctionPointer resolve_sys(const char *);
QAtomicInt loadHintsInt;
/// counts how many QLibrary or QPluginLoader are attached to us, plus 1 if it's loaded /// counts how many QLibrary or QPluginLoader are attached to us, plus 1 if it's loaded
QAtomicInt libraryRefCount; QAtomicInt libraryRefCount;
/// counts how many times load() or loadPlugin() were called /// counts how many times load() or loadPlugin() were called

View File

@ -162,6 +162,7 @@ bool QLibraryPrivate::load_sys()
dlFlags |= BIND_DEFERRED; dlFlags |= BIND_DEFERRED;
} }
#else #else
int loadHints = this->loadHints();
if (loadHints & QLibrary::ResolveAllSymbolsHint) { if (loadHints & QLibrary::ResolveAllSymbolsHint) {
dlFlags |= RTLD_NOW; dlFlags |= RTLD_NOW;
} else { } else {

View File

@ -339,7 +339,7 @@ void QPluginLoader::setFileName(const QString &fileName)
#if defined(QT_SHARED) #if defined(QT_SHARED)
QLibrary::LoadHints lh; QLibrary::LoadHints lh;
if (d) { if (d) {
lh = d->loadHints; lh = d->loadHints();
d->release(); d->release();
d = 0; d = 0;
did_load = false; did_load = false;
@ -405,17 +405,12 @@ void QPluginLoader::setLoadHints(QLibrary::LoadHints loadHints)
d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
d->errorString.clear(); d->errorString.clear();
} }
d->loadHints = loadHints; d->setLoadHints(loadHints);
} }
QLibrary::LoadHints QPluginLoader::loadHints() const QLibrary::LoadHints QPluginLoader::loadHints() const
{ {
if (!d) { return d ? d->loadHints() : QLibrary::LoadHints();
QPluginLoader *that = const_cast<QPluginLoader *>(this);
that->d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
that->d->errorString.clear();
}
return d->loadHints;
} }
/*! /*!

View File

@ -460,6 +460,14 @@ void tst_QLibrary::loadHints()
library.setFileName(lib); library.setFileName(lib);
QCOMPARE(library.loadHints(), lh); QCOMPARE(library.loadHints(), lh);
bool ok = library.load(); bool ok = library.load();
// we can't change the hints anymore
library.setLoadHints(QLibrary::LoadHints());
QCOMPARE(library.loadHints(), lh);
// confirm that a new QLibrary inherits the hints too
QCOMPARE(QLibrary(lib).loadHints(), lh);
if ( result ) { if ( result ) {
QVERIFY( ok ); QVERIFY( ok );
QVERIFY(library.unload()); QVERIFY(library.unload());