diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 0850a47aa..ab49ef8c3 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -4547,7 +4548,6 @@ int main(int argc, const char **argv) CCmdlineFix CmdlineFix(&argc, &argv); bool Silent = false; - bool RandInitFailed = false; for(int i = 1; i < argc; i++) { @@ -4582,17 +4582,42 @@ int main(int argc, const char **argv) vpLoggers.push_back(pFutureAssertionLogger); log_set_global_logger(log_logger_collection(std::move(vpLoggers)).release()); - if(secure_random_init() != 0) - { - RandInitFailed = true; - } + std::stack> CleanerFunctions; + std::function PerformCleanup = [&CleanerFunctions]() mutable { + while(!CleanerFunctions.empty()) + { + CleanerFunctions.top()(); + CleanerFunctions.pop(); + } + }; + std::function PerformFinalCleanup = []() { +#ifdef CONF_PLATFORM_ANDROID + // properly close this native thread, so globals are destructed + std::exit(0); +#endif + }; + std::function PerformAllCleanup = [PerformCleanup, PerformFinalCleanup]() mutable { + PerformCleanup(); + PerformFinalCleanup(); + }; + + const bool RandInitFailed = secure_random_init() != 0; + if(!RandInitFailed) + CleanerFunctions.push([]() { secure_random_uninit(); }); NotificationsInit(); + CleanerFunctions.push([]() { NotificationsUninit(); }); CClient *pClient = CreateClient(); IKernel *pKernel = IKernel::Create(); pKernel->RegisterInterface(pClient, false); pClient->RegisterInterfaces(); + CleanerFunctions.push([pKernel, pClient]() { + pKernel->Shutdown(); + delete pKernel; + pClient->~CClient(); + free(pClient); + }); const std::thread::id MainThreadId = std::this_thread::get_id(); dbg_assert_set_handler([MainThreadId, pClient](const char *pMsg) { @@ -4604,6 +4629,7 @@ int main(int argc, const char **argv) char aMessage[512]; str_format(aMessage, sizeof(aMessage), "An assertion error occured. Please write down or take a screenshot of the following information and report this error.\nPlease also share the assert log which you should find in the 'dumps' folder in your config directory.\n\n%s\n\nPlatform: %s\nGame version: %s %s\nOS version: %s", pMsg, CONF_PLATFORM_STRING, GAME_RELEASE_VERSION, GIT_SHORTREV_HASH != nullptr ? GIT_SHORTREV_HASH : "", aVersionStr); pClient->ShowMessageBox("Assertion Error", aMessage); + // Client will crash due to assertion, don't call PerformAllCleanup in this inconsistent state }); // create the components @@ -4634,6 +4660,7 @@ int main(int argc, const char **argv) const char *pError = "Failed to initialize the secure RNG."; dbg_msg("secure", "%s", pError); pClient->ShowMessageBox("Secure RNG Error", pError); + PerformAllCleanup(); return -1; } @@ -4668,9 +4695,7 @@ int main(int argc, const char **argv) const char *pError = "Failed to register an interface."; dbg_msg("client", "%s", pError); pClient->ShowMessageBox("Kernel Error", pError); - delete pKernel; - pClient->~CClient(); - free(pClient); + PerformAllCleanup(); return -1; } } @@ -4695,6 +4720,7 @@ int main(int argc, const char **argv) const char *pError = "Failed to load config from '" CONFIG_FILE "'."; dbg_msg("client", "%s", pError); pClient->ShowMessageBox("Config File Error", pError); + PerformAllCleanup(); return -1; } } @@ -4763,12 +4789,10 @@ int main(int argc, const char **argv) str_format(aError, sizeof(aError), "Unable to initialize SDL base: %s", SDL_GetError()); dbg_msg("client", "%s", aError); pClient->ShowMessageBox("SDL Error", aError); + PerformAllCleanup(); return -1; } - -#ifndef CONF_PLATFORM_ANDROID - atexit(SDL_Quit); -#endif + CleanerFunctions.push([]() { SDL_Quit(); }); // run the client dbg_msg("client", "starting..."); @@ -4781,23 +4805,14 @@ int main(int argc, const char **argv) pStorage->GetBinaryPath(PLAT_CLIENT_EXEC, aRestartBinaryPath, sizeof(aRestartBinaryPath)); } - pClient->~CClient(); - free(pClient); - pKernel->Shutdown(); - delete pKernel; - SDL_Quit(); - NotificationsUninit(); - secure_random_uninit(); + PerformCleanup(); if(Restarting) { shell_execute(aRestartBinaryPath); } -#ifdef CONF_PLATFORM_ANDROID - // properly close this native thread, so globals are destructed - std::exit(0); -#endif + PerformFinalCleanup(); return 0; }