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:
parent
800d0076e0
commit
cfaf851e26
@ -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 */
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -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());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user