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>
This commit is contained in:
parent
ef92ac5636
commit
ae6f73e856
@ -407,7 +407,7 @@ inline void QLibraryStore::cleanup()
|
|||||||
QLibraryPrivate *lib = it.value();
|
QLibraryPrivate *lib = it.value();
|
||||||
if (lib->libraryRefCount.loadRelaxed() == 1) {
|
if (lib->libraryRefCount.loadRelaxed() == 1) {
|
||||||
if (lib->libraryUnloadCount.loadRelaxed() > 0) {
|
if (lib->libraryUnloadCount.loadRelaxed() > 0) {
|
||||||
Q_ASSERT(lib->pHnd);
|
Q_ASSERT(lib->pHnd.loadRelaxed());
|
||||||
lib->libraryUnloadCount.storeRelaxed(1);
|
lib->libraryUnloadCount.storeRelaxed(1);
|
||||||
#ifdef __GLIBC__
|
#ifdef __GLIBC__
|
||||||
// glibc has a bug in unloading from global destructors
|
// 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)
|
QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints)
|
||||||
: pHnd(0), fileName(canonicalFileName), fullVersion(version),
|
: fileName(canonicalFileName), fullVersion(version), pluginState(MightBeAPlugin)
|
||||||
libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin)
|
|
||||||
{
|
{
|
||||||
loadHintsInt.storeRelaxed(loadHints);
|
loadHintsInt.storeRelaxed(loadHints);
|
||||||
if (canonicalFileName.isEmpty())
|
if (canonicalFileName.isEmpty())
|
||||||
@ -519,7 +518,7 @@ QLibraryPrivate::~QLibraryPrivate()
|
|||||||
void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
|
void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
|
||||||
{
|
{
|
||||||
// if the library is already loaded, we can't change the load hints
|
// if the library is already loaded, we can't change the load hints
|
||||||
if (pHnd)
|
if (pHnd.loadRelaxed())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loadHintsInt.storeRelaxed(lh);
|
loadHintsInt.storeRelaxed(lh);
|
||||||
@ -527,7 +526,7 @@ void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
|
|||||||
|
|
||||||
QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
|
QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
|
||||||
{
|
{
|
||||||
if (!pHnd)
|
if (!pHnd.loadRelaxed())
|
||||||
return 0;
|
return 0;
|
||||||
return resolve_sys(symbol);
|
return resolve_sys(symbol);
|
||||||
}
|
}
|
||||||
@ -542,7 +541,7 @@ void QLibraryPrivate::setLoadHints(QLibrary::LoadHints lh)
|
|||||||
QObject *QLibraryPrivate::pluginInstance()
|
QObject *QLibraryPrivate::pluginInstance()
|
||||||
{
|
{
|
||||||
// first, check if the instance is cached and hasn't been deleted
|
// first, check if the instance is cached and hasn't been deleted
|
||||||
QObject *obj = inst.data();
|
QObject *obj = (QMutexLocker(&mutex), inst.data());
|
||||||
if (obj)
|
if (obj)
|
||||||
return obj;
|
return obj;
|
||||||
|
|
||||||
@ -558,6 +557,7 @@ QObject *QLibraryPrivate::pluginInstance()
|
|||||||
obj = factory();
|
obj = factory();
|
||||||
|
|
||||||
// cache again
|
// cache again
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
if (inst)
|
if (inst)
|
||||||
obj = inst;
|
obj = inst;
|
||||||
else
|
else
|
||||||
@ -567,7 +567,7 @@ QObject *QLibraryPrivate::pluginInstance()
|
|||||||
|
|
||||||
bool QLibraryPrivate::load()
|
bool QLibraryPrivate::load()
|
||||||
{
|
{
|
||||||
if (pHnd) {
|
if (pHnd.loadRelaxed()) {
|
||||||
libraryUnloadCount.ref();
|
libraryUnloadCount.ref();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -576,7 +576,9 @@ bool QLibraryPrivate::load()
|
|||||||
|
|
||||||
Q_TRACE(QLibraryPrivate_load_entry, fileName);
|
Q_TRACE(QLibraryPrivate_load_entry, fileName);
|
||||||
|
|
||||||
|
mutex.lock();
|
||||||
bool ret = load_sys();
|
bool ret = load_sys();
|
||||||
|
mutex.unlock();
|
||||||
if (qt_debug_component()) {
|
if (qt_debug_component()) {
|
||||||
if (ret) {
|
if (ret) {
|
||||||
qDebug() << "loaded library" << fileName;
|
qDebug() << "loaded library" << fileName;
|
||||||
@ -599,9 +601,10 @@ bool QLibraryPrivate::load()
|
|||||||
|
|
||||||
bool QLibraryPrivate::unload(UnloadFlag flag)
|
bool QLibraryPrivate::unload(UnloadFlag flag)
|
||||||
{
|
{
|
||||||
if (!pHnd)
|
if (!pHnd.loadRelaxed())
|
||||||
return false;
|
return false;
|
||||||
if (libraryUnloadCount.loadRelaxed() > 0 && !libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
|
if (libraryUnloadCount.loadRelaxed() > 0 && !libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
delete inst.data();
|
delete inst.data();
|
||||||
if (flag == NoUnloadSys || unload_sys()) {
|
if (flag == NoUnloadSys || unload_sys()) {
|
||||||
if (qt_debug_component())
|
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'
|
//when the library is unloaded, we release the reference on it so that 'this'
|
||||||
//can get deleted
|
//can get deleted
|
||||||
libraryRefCount.deref();
|
libraryRefCount.deref();
|
||||||
pHnd = 0;
|
pHnd.storeRelaxed(nullptr);
|
||||||
instanceFactory.storeRelaxed(nullptr);
|
instanceFactory.storeRelaxed(nullptr);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (pHnd == 0);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QLibraryPrivate::release()
|
void QLibraryPrivate::release()
|
||||||
@ -746,6 +750,7 @@ bool QLibraryPrivate::isPlugin()
|
|||||||
|
|
||||||
void QLibraryPrivate::updatePluginState()
|
void QLibraryPrivate::updatePluginState()
|
||||||
{
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
errorString.clear();
|
errorString.clear();
|
||||||
if (pluginState != MightBeAPlugin)
|
if (pluginState != MightBeAPlugin)
|
||||||
return;
|
return;
|
||||||
@ -766,7 +771,7 @@ void QLibraryPrivate::updatePluginState()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!pHnd) {
|
if (!pHnd.loadRelaxed()) {
|
||||||
// scan for the plugin metadata without loading
|
// scan for the plugin metadata without loading
|
||||||
success = findPatternUnloaded(fileName, this);
|
success = findPatternUnloaded(fileName, this);
|
||||||
} else {
|
} else {
|
||||||
@ -830,7 +835,7 @@ bool QLibrary::load()
|
|||||||
if (!d)
|
if (!d)
|
||||||
return false;
|
return false;
|
||||||
if (did_load)
|
if (did_load)
|
||||||
return d->pHnd;
|
return d->pHnd.loadRelaxed();
|
||||||
did_load = true;
|
did_load = true;
|
||||||
return d->load();
|
return d->load();
|
||||||
}
|
}
|
||||||
@ -866,7 +871,7 @@ bool QLibrary::unload()
|
|||||||
*/
|
*/
|
||||||
bool QLibrary::isLoaded() const
|
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
|
QString QLibrary::fileName() const
|
||||||
{
|
{
|
||||||
if (d)
|
if (d) {
|
||||||
|
QMutexLocker locker(&d->mutex);
|
||||||
return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName;
|
return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName;
|
||||||
|
}
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1119,7 +1126,12 @@ QFunctionPointer QLibrary::resolve(const QString &fileName, const QString &versi
|
|||||||
*/
|
*/
|
||||||
QString QLibrary::errorString() const
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -54,10 +54,10 @@
|
|||||||
|
|
||||||
#include <QtCore/private/qglobal_p.h>
|
#include <QtCore/private/qglobal_p.h>
|
||||||
#include "QtCore/qlibrary.h"
|
#include "QtCore/qlibrary.h"
|
||||||
|
#include "QtCore/qmutex.h"
|
||||||
#include "QtCore/qpointer.h"
|
#include "QtCore/qpointer.h"
|
||||||
#include "QtCore/qstringlist.h"
|
#include "QtCore/qstringlist.h"
|
||||||
#include "QtCore/qplugin.h"
|
#include "QtCore/qplugin.h"
|
||||||
#include "QtCore/qsharedpointer.h"
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
# include "QtCore/qt_windows.h"
|
# include "QtCore/qt_windows.h"
|
||||||
#endif
|
#endif
|
||||||
@ -72,18 +72,15 @@ class QLibraryStore;
|
|||||||
class QLibraryPrivate
|
class QLibraryPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
HINSTANCE
|
using Handle = HINSTANCE;
|
||||||
#else
|
#else
|
||||||
void *
|
using Handle = void *;
|
||||||
#endif
|
#endif
|
||||||
pHnd;
|
|
||||||
|
|
||||||
enum UnloadFlag { UnloadSys, NoUnloadSys };
|
enum UnloadFlag { UnloadSys, NoUnloadSys };
|
||||||
|
|
||||||
QString fileName, qualifiedFileName;
|
const QString fileName;
|
||||||
QString fullVersion;
|
const QString fullVersion;
|
||||||
|
|
||||||
bool load();
|
bool load();
|
||||||
QtPluginInstanceFunction loadPlugin(); // loads and resolves instance
|
QtPluginInstanceFunction loadPlugin(); // loads and resolves instance
|
||||||
@ -94,17 +91,22 @@ public:
|
|||||||
QLibrary::LoadHints loadHints() const
|
QLibrary::LoadHints loadHints() const
|
||||||
{ return QLibrary::LoadHints(loadHintsInt.loadRelaxed()); }
|
{ return QLibrary::LoadHints(loadHintsInt.loadRelaxed()); }
|
||||||
void setLoadHints(QLibrary::LoadHints lh);
|
void setLoadHints(QLibrary::LoadHints lh);
|
||||||
|
QObject *pluginInstance();
|
||||||
|
|
||||||
static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString(),
|
static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString(),
|
||||||
QLibrary::LoadHints loadHints = nullptr);
|
QLibrary::LoadHints loadHints = nullptr);
|
||||||
static QStringList suffixes_sys(const QString &fullVersion);
|
static QStringList suffixes_sys(const QString &fullVersion);
|
||||||
static QStringList prefixes_sys();
|
static QStringList prefixes_sys();
|
||||||
|
|
||||||
QPointer<QObject> inst; // used by QFactoryLoader
|
|
||||||
QAtomicPointer<std::remove_pointer<QtPluginInstanceFunction>::type> instanceFactory;
|
QAtomicPointer<std::remove_pointer<QtPluginInstanceFunction>::type> instanceFactory;
|
||||||
QJsonObject metaData;
|
QAtomicPointer<std::remove_pointer<Handle>::type> pHnd;
|
||||||
|
|
||||||
|
// the mutex protects the fields below
|
||||||
|
QMutex mutex;
|
||||||
|
QPointer<QObject> inst; // used by QFactoryLoader
|
||||||
|
QJsonObject metaData;
|
||||||
QString errorString;
|
QString errorString;
|
||||||
|
QString qualifiedFileName;
|
||||||
|
|
||||||
void updatePluginState();
|
void updatePluginState();
|
||||||
bool isPlugin();
|
bool isPlugin();
|
||||||
|
@ -214,8 +214,9 @@ bool QLibraryPrivate::load_sys()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool retry = true;
|
bool retry = true;
|
||||||
for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) {
|
Handle hnd = nullptr;
|
||||||
for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) {
|
for (int prefix = 0; retry && !hnd && prefix < prefixes.size(); prefix++) {
|
||||||
|
for (int suffix = 0; retry && !hnd && suffix < suffixes.size(); suffix++) {
|
||||||
if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix)))
|
if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix)))
|
||||||
continue;
|
continue;
|
||||||
if (path.isEmpty() && prefixes.at(prefix).contains(QLatin1Char('/')))
|
if (path.isEmpty() && prefixes.at(prefix).contains(QLatin1Char('/')))
|
||||||
@ -232,7 +233,7 @@ bool QLibraryPrivate::load_sys()
|
|||||||
attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix);
|
attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
pHnd = dlopen(QFile::encodeName(attempt), dlFlags);
|
hnd = dlopen(QFile::encodeName(attempt), dlFlags);
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
if (!pHnd) {
|
if (!pHnd) {
|
||||||
auto attemptFromBundle = attempt;
|
auto attemptFromBundle = attempt;
|
||||||
@ -248,7 +249,7 @@ bool QLibraryPrivate::load_sys()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) {
|
if (!hnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) {
|
||||||
// We only want to continue if dlopen failed due to that the shared library did not exist.
|
// We only want to continue if dlopen failed due to that the shared library did not exist.
|
||||||
// However, we are only able to apply this check for absolute filenames (since they are
|
// However, we are only able to apply this check for absolute filenames (since they are
|
||||||
// not influenced by the content of LD_LIBRARY_PATH, /etc/ld.so.cache, DT_RPATH etc...)
|
// not influenced by the content of LD_LIBRARY_PATH, /etc/ld.so.cache, DT_RPATH etc...)
|
||||||
@ -259,7 +260,7 @@ bool QLibraryPrivate::load_sys()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
if (!pHnd) {
|
if (!hnd) {
|
||||||
QByteArray utf8Bundle = fileName.toUtf8();
|
QByteArray utf8Bundle = fileName.toUtf8();
|
||||||
QCFType<CFURLRef> bundleUrl = CFURLCreateFromFileSystemRepresentation(NULL, reinterpret_cast<const UInt8*>(utf8Bundle.data()), utf8Bundle.length(), true);
|
QCFType<CFURLRef> bundleUrl = CFURLCreateFromFileSystemRepresentation(NULL, reinterpret_cast<const UInt8*>(utf8Bundle.data()), utf8Bundle.length(), true);
|
||||||
QCFType<CFBundleRef> bundle = CFBundleCreate(NULL, bundleUrl);
|
QCFType<CFBundleRef> bundle = CFBundleCreate(NULL, bundleUrl);
|
||||||
@ -268,23 +269,24 @@ bool QLibraryPrivate::load_sys()
|
|||||||
char executableFile[FILENAME_MAX];
|
char executableFile[FILENAME_MAX];
|
||||||
CFURLGetFileSystemRepresentation(url, true, reinterpret_cast<UInt8*>(executableFile), FILENAME_MAX);
|
CFURLGetFileSystemRepresentation(url, true, reinterpret_cast<UInt8*>(executableFile), FILENAME_MAX);
|
||||||
attempt = QString::fromUtf8(executableFile);
|
attempt = QString::fromUtf8(executableFile);
|
||||||
pHnd = dlopen(QFile::encodeName(attempt), dlFlags);
|
hnd = dlopen(QFile::encodeName(attempt), dlFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!pHnd) {
|
if (!hnd) {
|
||||||
errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName, qdlerror());
|
errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName, qdlerror());
|
||||||
}
|
}
|
||||||
if (pHnd) {
|
if (hnd) {
|
||||||
qualifiedFileName = attempt;
|
qualifiedFileName = attempt;
|
||||||
errorString.clear();
|
errorString.clear();
|
||||||
}
|
}
|
||||||
return (pHnd != 0);
|
pHnd.storeRelaxed(hnd);
|
||||||
|
return (hnd != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QLibraryPrivate::unload_sys()
|
bool QLibraryPrivate::unload_sys()
|
||||||
{
|
{
|
||||||
if (dlclose(pHnd)) {
|
if (dlclose(pHnd.loadAcquire())) {
|
||||||
#if defined (Q_OS_QNX) // Workaround until fixed in QNX; fixes crash in
|
#if defined (Q_OS_QNX) // Workaround until fixed in QNX; fixes crash in
|
||||||
char *error = dlerror(); // QtDeclarative auto test "qqmlenginecleanup" for instance
|
char *error = dlerror(); // QtDeclarative auto test "qqmlenginecleanup" for instance
|
||||||
if (!qstrcmp(error, "Shared objects still referenced")) // On QNX that's only "informative"
|
if (!qstrcmp(error, "Shared objects still referenced")) // On QNX that's only "informative"
|
||||||
@ -316,7 +318,7 @@ Q_CORE_EXPORT QFunctionPointer qt_mac_resolve_sys(void *handle, const char *symb
|
|||||||
|
|
||||||
QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol)
|
QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol)
|
||||||
{
|
{
|
||||||
QFunctionPointer address = QFunctionPointer(dlsym(pHnd, symbol));
|
QFunctionPointer address = QFunctionPointer(dlsym(pHnd.loadAcquire(), symbol));
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,26 +95,27 @@ bool QLibraryPrivate::load_sys()
|
|||||||
attempts.prepend(QDir::rootPath() + fileName);
|
attempts.prepend(QDir::rootPath() + fileName);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Handle hnd = nullptr;
|
||||||
for (const QString &attempt : qAsConst(attempts)) {
|
for (const QString &attempt : qAsConst(attempts)) {
|
||||||
#ifndef Q_OS_WINRT
|
#ifndef Q_OS_WINRT
|
||||||
pHnd = LoadLibrary(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(attempt).utf16()));
|
hnd = LoadLibrary(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(attempt).utf16()));
|
||||||
#else // Q_OS_WINRT
|
#else // Q_OS_WINRT
|
||||||
QString path = QDir::toNativeSeparators(QDir::current().relativeFilePath(attempt));
|
QString path = QDir::toNativeSeparators(QDir::current().relativeFilePath(attempt));
|
||||||
pHnd = LoadPackagedLibrary(reinterpret_cast<LPCWSTR>(path.utf16()), 0);
|
hnd = LoadPackagedLibrary(reinterpret_cast<LPCWSTR>(path.utf16()), 0);
|
||||||
if (pHnd)
|
if (hnd)
|
||||||
qualifiedFileName = attempt;
|
qualifiedFileName = attempt;
|
||||||
#endif // !Q_OS_WINRT
|
#endif // !Q_OS_WINRT
|
||||||
|
|
||||||
// If we have a handle or the last error is something other than "unable
|
// If we have a handle or the last error is something other than "unable
|
||||||
// to find the module", then bail out
|
// to find the module", then bail out
|
||||||
if (pHnd || ::GetLastError() != ERROR_MOD_NOT_FOUND)
|
if (hnd || ::GetLastError() != ERROR_MOD_NOT_FOUND)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef Q_OS_WINRT
|
#ifndef Q_OS_WINRT
|
||||||
SetErrorMode(oldmode);
|
SetErrorMode(oldmode);
|
||||||
#endif
|
#endif
|
||||||
if (!pHnd) {
|
if (!hnd) {
|
||||||
errorString = QLibrary::tr("Cannot load library %1: %2").arg(
|
errorString = QLibrary::tr("Cannot load library %1: %2").arg(
|
||||||
QDir::toNativeSeparators(fileName), qt_error_string());
|
QDir::toNativeSeparators(fileName), qt_error_string());
|
||||||
} else {
|
} else {
|
||||||
@ -123,7 +124,7 @@ bool QLibraryPrivate::load_sys()
|
|||||||
|
|
||||||
#ifndef Q_OS_WINRT
|
#ifndef Q_OS_WINRT
|
||||||
wchar_t buffer[MAX_PATH];
|
wchar_t buffer[MAX_PATH];
|
||||||
::GetModuleFileName(pHnd, buffer, MAX_PATH);
|
::GetModuleFileName(hnd, buffer, MAX_PATH);
|
||||||
|
|
||||||
QString moduleFileName = QString::fromWCharArray(buffer);
|
QString moduleFileName = QString::fromWCharArray(buffer);
|
||||||
moduleFileName.remove(0, 1 + moduleFileName.lastIndexOf(QLatin1Char('\\')));
|
moduleFileName.remove(0, 1 + moduleFileName.lastIndexOf(QLatin1Char('\\')));
|
||||||
@ -138,19 +139,20 @@ bool QLibraryPrivate::load_sys()
|
|||||||
HMODULE hmod;
|
HMODULE hmod;
|
||||||
bool ok = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN |
|
bool ok = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN |
|
||||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||||
reinterpret_cast<const wchar_t *>(pHnd),
|
reinterpret_cast<const wchar_t *>(hnd),
|
||||||
&hmod);
|
&hmod);
|
||||||
Q_ASSERT(!ok || hmod == pHnd);
|
Q_ASSERT(!ok || hmod == hnd);
|
||||||
Q_UNUSED(ok);
|
Q_UNUSED(ok);
|
||||||
}
|
}
|
||||||
#endif // !Q_OS_WINRT
|
#endif // !Q_OS_WINRT
|
||||||
}
|
}
|
||||||
return (pHnd != 0);
|
pHnd.storeRelaxed(hnd);
|
||||||
|
return (pHnd != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QLibraryPrivate::unload_sys()
|
bool QLibraryPrivate::unload_sys()
|
||||||
{
|
{
|
||||||
if (!FreeLibrary(pHnd)) {
|
if (!FreeLibrary(pHnd.loadAcquire())) {
|
||||||
errorString = QLibrary::tr("Cannot unload library %1: %2").arg(
|
errorString = QLibrary::tr("Cannot unload library %1: %2").arg(
|
||||||
QDir::toNativeSeparators(fileName), qt_error_string());
|
QDir::toNativeSeparators(fileName), qt_error_string());
|
||||||
return false;
|
return false;
|
||||||
@ -161,7 +163,7 @@ bool QLibraryPrivate::unload_sys()
|
|||||||
|
|
||||||
QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol)
|
QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol)
|
||||||
{
|
{
|
||||||
FARPROC address = GetProcAddress(pHnd, symbol);
|
FARPROC address = GetProcAddress(pHnd.loadAcquire(), symbol);
|
||||||
return QFunctionPointer(address);
|
return QFunctionPointer(address);
|
||||||
}
|
}
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -196,9 +196,7 @@ QObject *QPluginLoader::instance()
|
|||||||
{
|
{
|
||||||
if (!isLoaded() && !load())
|
if (!isLoaded() && !load())
|
||||||
return 0;
|
return 0;
|
||||||
if (!d->inst && d->instance)
|
return d->pluginInstance();
|
||||||
d->inst = d->instance();
|
|
||||||
return d->inst.data();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -233,7 +231,7 @@ bool QPluginLoader::load()
|
|||||||
if (!d || d->fileName.isEmpty())
|
if (!d || d->fileName.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
if (did_load)
|
if (did_load)
|
||||||
return d->pHnd && d->instance;
|
return d->pHnd && d->instanceFactory.loadAcquire();
|
||||||
if (!d->isPlugin())
|
if (!d->isPlugin())
|
||||||
return false;
|
return false;
|
||||||
did_load = true;
|
did_load = true;
|
||||||
@ -275,7 +273,7 @@ bool QPluginLoader::unload()
|
|||||||
*/
|
*/
|
||||||
bool QPluginLoader::isLoaded() const
|
bool QPluginLoader::isLoaded() const
|
||||||
{
|
{
|
||||||
return d && d->pHnd && d->instance;
|
return d && d->pHnd && d->instanceFactory.loadRelaxed();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(QT_SHARED)
|
#if defined(QT_SHARED)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user