Don't allow the QLibraryStore to be recreated during shutdown

When QtCore's global destructors are run, they delete the global
QLibraryStore qt_library_data and set the pointer to null. If something
happened to call QLibraryStore::instance() later, it would be recreated
and then weird things might happen. So prevent that from happening.

That usually cannot happen, since the only thing that can run after
QtCore global destructors are other QtCore global destructors or global
destructors from libraries that do not depend on QtCore. So we're
reasonably safe. There are two conditions in which something could run
after QLibraryStore::cleanup() and still try to access QLibraryStore:

1) indirect dependency, like a global destructor from a library that
doesn't depend on QtCore running code from another module that does.

2) static builds of Qt modules. In that case, the order of the global
destructors is totally arbitrary and we could get one from a module that
depends on QtCore running after QtCore's. That is the case from the bug
report.

Task-number: QTBUG-36294
Change-Id: Id199671275fd2535acf2d158857ce46b474e579b
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
Reviewed-by: Tim Jenssen <tim.jenssen@digia.com>
This commit is contained in:
Thiago Macieira 2014-01-20 11:53:21 -08:00 committed by The Qt Project
parent 2a2936b335
commit 5aee85ec23

View File

@ -374,6 +374,7 @@ private:
static QBasicMutex qt_library_mutex; static QBasicMutex qt_library_mutex;
static QLibraryStore *qt_library_data = 0; static QLibraryStore *qt_library_data = 0;
static bool qt_library_data_once;
QLibraryStore::~QLibraryStore() QLibraryStore::~QLibraryStore()
{ {
@ -429,8 +430,11 @@ Q_DESTRUCTOR_FUNCTION(qlibraryCleanup)
// must be called with a locked mutex // must be called with a locked mutex
QLibraryStore *QLibraryStore::instance() QLibraryStore *QLibraryStore::instance()
{ {
if (Q_UNLIKELY(!qt_library_data)) if (Q_UNLIKELY(!qt_library_data_once && !qt_library_data)) {
// only create once per process lifetime
qt_library_data = new QLibraryStore; qt_library_data = new QLibraryStore;
qt_library_data_once = true;
}
return qt_library_data; return qt_library_data;
} }
@ -440,11 +444,14 @@ inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, con
QLibraryStore *data = instance(); QLibraryStore *data = instance();
// check if this library is already loaded // check if this library is already loaded
QLibraryPrivate *lib = data->libraryMap.value(fileName); QLibraryPrivate *lib = 0;
if (Q_LIKELY(data))
lib = data->libraryMap.value(fileName);
if (!lib) if (!lib)
lib = new QLibraryPrivate(fileName, version); lib = new QLibraryPrivate(fileName, version);
// track this library // track this library
if (Q_LIKELY(data))
data->libraryMap.insert(fileName, lib); data->libraryMap.insert(fileName, lib);
lib->libraryRefCount.ref(); lib->libraryRefCount.ref();
@ -464,9 +471,11 @@ inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib)
// no one else is using // no one else is using
Q_ASSERT(lib->libraryUnloadCount.load() == 0); Q_ASSERT(lib->libraryUnloadCount.load() == 0);
if (Q_LIKELY(data)) {
QLibraryPrivate *that = data->libraryMap.take(lib->fileName); QLibraryPrivate *that = data->libraryMap.take(lib->fileName);
Q_ASSERT(lib == that); Q_ASSERT(lib == that);
Q_UNUSED(that); Q_UNUSED(that);
}
delete lib; delete lib;
} }