mirror of
https://github.com/lubosz/overte.git
synced 2025-04-09 12:12:30 +02:00
Fix crash when passing --checkMinSpec flag
That flag caused a DLL to be loaded before Application was instanced. This triggers a Qt bug inside Q_COREAPP_STARTUP_FUNC that causes the previous registration pointing the startup function in the main executable to be overridden with the address of the function in the DLL (Since they both link the same static library) This leads to the correct function running in the wrong address space (the DLLs), hence not initializing some global variables correctly.
This commit is contained in:
parent
9ba1532c26
commit
80c0f2a21e
10 changed files with 68 additions and 73 deletions
|
@ -23,9 +23,12 @@ int main(int argc, char* argv[]) {
|
|||
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
setupGlobalInstances();
|
||||
|
||||
qInstallMessageHandler(LogHandler::verboseMessageHandler);
|
||||
qInfo() << "Starting.";
|
||||
|
||||
|
||||
AssignmentClientApp app(argc, argv);
|
||||
|
||||
int acReturn = app.exec();
|
||||
|
|
|
@ -29,6 +29,8 @@ int main(int argc, char* argv[]) {
|
|||
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
setupGlobalInstances();
|
||||
|
||||
Setting::init();
|
||||
|
||||
#ifndef WIN32
|
||||
|
|
|
@ -62,6 +62,8 @@ int main(int argc, const char* argv[]) {
|
|||
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
setupGlobalInstances();
|
||||
|
||||
Setting::init();
|
||||
|
||||
// Instance UserActivityLogger now that the settings are loaded
|
||||
|
|
|
@ -23,43 +23,53 @@
|
|||
#include "SharedUtil.h"
|
||||
|
||||
namespace Setting {
|
||||
static QSharedPointer<Manager> globalManager;
|
||||
|
||||
// cleans up the settings private instance. Should only be run once at closing down.
|
||||
void cleanupPrivateInstance() {
|
||||
auto globalManager = DependencyManager::get<Manager>();
|
||||
Q_ASSERT(qApp && globalManager);
|
||||
|
||||
// grab the thread before we nuke the instance
|
||||
QThread* settingsManagerThread = DependencyManager::get<Manager>()->thread();
|
||||
QThread* settingsManagerThread = globalManager->thread();
|
||||
|
||||
// tell the private instance to clean itself up on its thread
|
||||
DependencyManager::destroy<Manager>();
|
||||
|
||||
globalManager.reset();
|
||||
|
||||
// quit the settings manager thread and wait on it to make sure it's gone
|
||||
// quit the settings manager thread
|
||||
settingsManagerThread->quit();
|
||||
settingsManagerThread->wait();
|
||||
|
||||
// Save all settings
|
||||
globalManager->saveAll();
|
||||
|
||||
qCDebug(shared) << "Settings thread stopped.";
|
||||
}
|
||||
|
||||
void setupPrivateInstance() {
|
||||
// Ensure Setting::init has already ran and qApp exists
|
||||
if (qApp && globalManager) {
|
||||
// Let's set up the settings Private instance on its own thread
|
||||
QThread* thread = new QThread();
|
||||
Q_CHECK_PTR(thread);
|
||||
thread->setObjectName("Settings Thread");
|
||||
auto globalManager = DependencyManager::get<Manager>();
|
||||
Q_ASSERT(qApp && globalManager);
|
||||
|
||||
QObject::connect(thread, SIGNAL(started()), globalManager.data(), SLOT(startTimer()));
|
||||
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
||||
QObject::connect(thread, SIGNAL(finished()), globalManager.data(), SLOT(deleteLater()));
|
||||
globalManager->moveToThread(thread);
|
||||
thread->start();
|
||||
qCDebug(shared) << "Settings thread started.";
|
||||
// Let's set up the settings private instance on its own thread
|
||||
QThread* thread = new QThread(qApp);
|
||||
Q_CHECK_PTR(thread);
|
||||
thread->setObjectName("Settings Thread");
|
||||
|
||||
// Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
|
||||
qAddPostRoutine(cleanupPrivateInstance);
|
||||
}
|
||||
// Setup setting periodical save timer
|
||||
QObject::connect(thread, &QThread::started, globalManager.data(), &Manager::startTimer);
|
||||
QObject::connect(thread, &QThread::finished, globalManager.data(), &Manager::stopTimer);
|
||||
|
||||
// Setup manager threading affinity
|
||||
globalManager->moveToThread(thread);
|
||||
QObject::connect(thread, &QThread::finished, globalManager.data(), [] {
|
||||
auto globalManager = DependencyManager::get<Manager>();
|
||||
Q_ASSERT(qApp && globalManager);
|
||||
|
||||
// Move manager back to the main thread (has to be done on owning thread)
|
||||
globalManager->moveToThread(qApp->thread());
|
||||
});
|
||||
|
||||
thread->start();
|
||||
qCDebug(shared) << "Settings thread started.";
|
||||
|
||||
// Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
|
||||
qAddPostRoutine(cleanupPrivateInstance);
|
||||
}
|
||||
FIXED_Q_COREAPP_STARTUP_FUNCTION(setupPrivateInstance)
|
||||
|
||||
// Sets up the settings private instance. Should only be run once at startup. preInit() must be run beforehand,
|
||||
void init() {
|
||||
|
@ -68,6 +78,7 @@ namespace Setting {
|
|||
QSettings settings;
|
||||
qCDebug(shared) << "Settings file:" << settings.fileName();
|
||||
|
||||
// Backward compatibility for old settings file
|
||||
if (settings.allKeys().isEmpty()) {
|
||||
loadOldINIFile(settings);
|
||||
}
|
||||
|
@ -80,11 +91,13 @@ namespace Setting {
|
|||
qCDebug(shared) << (deleted ? "Deleted" : "Failed to delete") << "settings lock file" << settingsLockFilename;
|
||||
}
|
||||
|
||||
globalManager = DependencyManager::set<Manager>();
|
||||
// Setup settings manager
|
||||
DependencyManager::set<Manager>();
|
||||
|
||||
setupPrivateInstance();
|
||||
// Add pre-routine to setup threading
|
||||
qAddPreRoutine(setupPrivateInstance);
|
||||
}
|
||||
|
||||
|
||||
void Interface::init() {
|
||||
if (!DependencyManager::isSet<Manager>()) {
|
||||
// WARNING: As long as we are using QSettings this should always be triggered for each Setting::Handle
|
||||
|
|
|
@ -23,11 +23,7 @@ namespace Setting {
|
|||
// Cleanup timer
|
||||
stopTimer();
|
||||
delete _saveTimer;
|
||||
|
||||
// Save all settings before exit
|
||||
saveAll();
|
||||
|
||||
// sync will be called in the QSettings destructor
|
||||
_saveTimer = nullptr;
|
||||
}
|
||||
|
||||
// Custom deleter does nothing, because we need to shutdown later than the dependency manager
|
||||
|
|
|
@ -63,12 +63,12 @@ extern "C" FILE * __cdecl __iob_func(void) {
|
|||
#include "OctalCode.h"
|
||||
#include "SharedLogging.h"
|
||||
|
||||
static std::mutex stagedGlobalInstancesMutex;
|
||||
static std::unordered_map<std::string, QVariant> stagedGlobalInstances;
|
||||
|
||||
|
||||
std::mutex& globalInstancesMutex() {
|
||||
static std::mutex mutex;
|
||||
return mutex;
|
||||
return stagedGlobalInstancesMutex;
|
||||
}
|
||||
|
||||
static void commitGlobalInstances() {
|
||||
|
@ -78,7 +78,10 @@ static void commitGlobalInstances() {
|
|||
}
|
||||
stagedGlobalInstances.clear();
|
||||
}
|
||||
FIXED_Q_COREAPP_STARTUP_FUNCTION(commitGlobalInstances)
|
||||
|
||||
void setupGlobalInstances() {
|
||||
qAddPreRoutine(commitGlobalInstances);
|
||||
}
|
||||
|
||||
QVariant getGlobalInstance(const char* propertyName) {
|
||||
if (qApp) {
|
||||
|
|
|
@ -25,23 +25,6 @@
|
|||
#include <QtCore/QCoreApplication>
|
||||
#include <QUuid>
|
||||
|
||||
// Workaround for https://bugreports.qt.io/browse/QTBUG-54479
|
||||
// Wrap target function inside another function that holds
|
||||
// a unique string identifier and uses it to ensure it only runs once
|
||||
// by storing a state within the qApp
|
||||
// We cannot used std::call_once with a static once_flag because
|
||||
// this is used in shared libraries that are linked by several DLLs
|
||||
// (ie. plugins), meaning the static will be useless in that case
|
||||
#define FIXED_Q_COREAPP_STARTUP_FUNCTION(AFUNC) \
|
||||
static void AFUNC ## _fixed() { \
|
||||
const auto propertyName = std::string(Q_FUNC_INFO) + __FILE__; \
|
||||
if (!qApp->property(propertyName.c_str()).toBool()) { \
|
||||
AFUNC(); \
|
||||
qApp->setProperty(propertyName.c_str(), QVariant(true)); \
|
||||
} \
|
||||
} \
|
||||
Q_COREAPP_STARTUP_FUNCTION(AFUNC ## _fixed)
|
||||
|
||||
// When writing out avatarEntities to a QByteArray, if the parentID is the ID of MyAvatar, use this ID instead. This allows
|
||||
// the value to be reset when the sessionID changes.
|
||||
const QUuid AVATAR_SELF_ID = QUuid("{00000000-0000-0000-0000-000000000001}");
|
||||
|
@ -53,21 +36,7 @@ std::unique_ptr<T>& globalInstancePointer() {
|
|||
return instancePtr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setGlobalInstance(const char* propertyName, T* instance) {
|
||||
globalInstancePointer<T>().reset(instance);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool destroyGlobalInstance() {
|
||||
std::unique_ptr<T>& instancePtr = globalInstancePointer<T>();
|
||||
if (instancePtr.get()) {
|
||||
instancePtr.reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setupGlobalInstances();
|
||||
std::mutex& globalInstancesMutex();
|
||||
QVariant getGlobalInstance(const char* propertyName);
|
||||
void setGlobalInstance(const char* propertyName, const QVariant& variant);
|
||||
|
@ -78,7 +47,6 @@ void setGlobalInstance(const char* propertyName, const QVariant& variant);
|
|||
template <typename T, typename... Args>
|
||||
T* globalInstance(const char* propertyName, Args&&... args) {
|
||||
static T* resultInstance { nullptr };
|
||||
static std::mutex mutex;
|
||||
if (!resultInstance) {
|
||||
std::unique_lock<std::mutex> lock(globalInstancesMutex());
|
||||
if (!resultInstance) {
|
||||
|
|
|
@ -19,15 +19,16 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int main(int argc, char* argv[]) {
|
||||
QCoreApplication::setApplicationName(BuildInfo::AC_CLIENT_SERVER_NAME);
|
||||
QCoreApplication::setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION);
|
||||
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
setupGlobalInstances();
|
||||
|
||||
Setting::init();
|
||||
|
||||
ACClientApp app(argc, argv);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
|
|
@ -25,9 +25,10 @@ int main(int argc, char * argv[]) {
|
|||
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
setupGlobalInstances();
|
||||
|
||||
Setting::init();
|
||||
|
||||
ATPClientApp app(argc, argv);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
|
|
@ -10,11 +10,17 @@
|
|||
|
||||
#include "Oven.h"
|
||||
|
||||
#include <BuildInfo.h>
|
||||
#include <SettingInterface.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
QCoreApplication::setOrganizationName("High Fidelity");
|
||||
QCoreApplication::setApplicationName("Oven");
|
||||
QCoreApplication::setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION);
|
||||
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
setupGlobalInstances();
|
||||
|
||||
// init the settings interface so we can save and load settings
|
||||
Setting::init();
|
||||
|
|
Loading…
Reference in a new issue