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)
: pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0),
loadHints(loadHints),
libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin)
{
loadHintsInt.store(loadHints);
if (canonicalFileName.isEmpty())
errorString = QLibrary::tr("The shared library was not found.");
}
@ -508,7 +508,7 @@ void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
if (pHnd)
return;
loadHints = lh;
loadHintsInt.store(lh);
}
QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
@ -518,6 +518,12 @@ QFunctionPointer QLibraryPrivate::resolve(const char *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()
{
@ -914,13 +920,12 @@ void QLibrary::setFileName(const QString &fileName)
{
QLibrary::LoadHints lh;
if (d) {
lh = d->loadHints;
lh = d->loadHints();
d->release();
d = 0;
did_load = false;
}
d = QLibraryPrivate::findOrCreate(fileName);
d->loadHints = lh;
d = QLibraryPrivate::findOrCreate(fileName, QString(), lh);
}
QString QLibrary::fileName() const
@ -943,13 +948,12 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum)
{
QLibrary::LoadHints lh;
if (d) {
lh = d->loadHints;
lh = d->loadHints();
d->release();
d = 0;
did_load = false;
}
d = QLibraryPrivate::findOrCreate(fileName, verNum >= 0 ? QString::number(verNum) : QString());
d->loadHints = lh;
d = QLibraryPrivate::findOrCreate(fileName, verNum >= 0 ? QString::number(verNum) : QString(), lh);
}
/*!
@ -965,13 +969,12 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver
{
QLibrary::LoadHints lh;
if (d) {
lh = d->loadHints;
lh = d->loadHints();
d->release();
d = 0;
did_load = false;
}
d = QLibraryPrivate::findOrCreate(fileName, version);
d->loadHints = lh;
d = QLibraryPrivate::findOrCreate(fileName, version, lh);
}
/*!
@ -1102,6 +1105,12 @@ QString QLibrary::errorString() const
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
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)
{
@ -1109,12 +1118,12 @@ void QLibrary::setLoadHints(LoadHints hints)
d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
d->errorString.clear();
}
d->loadHints = hints;
d->setLoadHints(hints);
}
QLibrary::LoadHints QLibrary::loadHints() const
{
return d ? d->loadHints : (QLibrary::LoadHints)0;
return d ? d->loadHints() : QLibrary::LoadHints();
}
/* Internal, for debugging */

View File

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

View File

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

View File

@ -339,7 +339,7 @@ void QPluginLoader::setFileName(const QString &fileName)
#if defined(QT_SHARED)
QLibrary::LoadHints lh;
if (d) {
lh = d->loadHints;
lh = d->loadHints();
d->release();
d = 0;
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->errorString.clear();
}
d->loadHints = loadHints;
d->setLoadHints(loadHints);
}
QLibrary::LoadHints QPluginLoader::loadHints() const
{
if (!d) {
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;
return d ? d->loadHints() : QLibrary::LoadHints();
}
/*!

View File

@ -460,6 +460,14 @@ void tst_QLibrary::loadHints()
library.setFileName(lib);
QCOMPARE(library.loadHints(), lh);
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 ) {
QVERIFY( ok );
QVERIFY(library.unload());