From 4330ff83cf21639471deb96e6021ac248e5cc57b Mon Sep 17 00:00:00 2001 From: Jupeyy Date: Fri, 18 Feb 2022 10:46:05 +0100 Subject: [PATCH 1/4] Add exception handling for Windows --- CMakeLists.txt | 17 ++++++++++++++++ cmake/FindExceptionHandling.cmake | 21 ++++++++++++++++++++ src/base/system.cpp | 33 +++++++++++++++++++++++++++++++ src/base/system.h | 5 +++++ src/engine/client/client.cpp | 14 +++++++++++++ src/engine/server/server.cpp | 14 +++++++++++++ 6 files changed, 104 insertions(+) create mode 100644 cmake/FindExceptionHandling.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 41d09f6aa..68318bb74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,8 @@ option(DISCORD_DYNAMIC "Enable discovering Discord rich presence libraries at ru option(PREFER_BUNDLED_LIBS "Prefer bundled libraries over system libraries" ${AUTO_DEPENDENCIES_DEFAULT}) option(DEV "Don't generate stuff necessary for packaging" OFF) +option(EXCEPTION_HANDLING "Enable exception handling (only works with Windows as of now)" OFF) + if(TEST_MYSQL) set(MYSQL ON) endif() @@ -217,6 +219,10 @@ if(NOT MSVC AND NOT HAIKU) add_c_compiler_flag_if_supported(OUR_FLAGS -stdlib=libc++) endif() + if(EXCEPTION_HANDLING) + add_c_compiler_flag_if_supported(OUR_FLAGS -DCONF_EXCEPTION_HANDLING) + endif() + add_c_compiler_flag_if_supported(OUR_FLAGS_OWN -Wall) if(CMAKE_VERSION VERSION_GREATER 3.3 OR CMAKE_VERSION VERSION_EQUAL 3.3) add_c_compiler_flag_if_supported(OUR_FLAGS_OWN @@ -239,6 +245,12 @@ if(NOT MSVC AND NOT HAIKU) #add_cxx_compiler_flag_if_supported(OUR_FLAGS_OWN "-Wuseless-cast") endif() +if(MSVC) + if(EXCEPTION_HANDLING) + add_c_compiler_flag_if_supported(OUR_FLAGS /DCONF_EXCEPTION_HANDLING) + endif() +endif() + if(NOT MSVC AND NOT HAIKU) check_c_compiler_flag("-O2;-Wp,-Werror;-D_FORTIFY_SOURCE=2" DEFINE_FORTIFY_SOURCE) # Some distributions define _FORTIFY_SOURCE by themselves. endif() @@ -440,6 +452,10 @@ else() set(WEBSOCKETS_INCLUDE_DIRS) endif() +if(EXCEPTION_HANDLING) + find_package(ExceptionHandling) +endif() + if(TARGET_OS AND TARGET_OS STREQUAL "mac") find_program(CMAKE_OTOOL otool) find_program(DMGBUILD dmgbuild) @@ -1399,6 +1415,7 @@ set(COPY_FILES ${FFMPEG_COPY_FILES} ${WEBSOCKETS_COPY_FILES} ${DISCORDSDK_COPY_FILES} + ${EXCEPTION_HANDLING_COPY_FILES} ) file(COPY ${COPY_FILES} DESTINATION .) diff --git a/cmake/FindExceptionHandling.cmake b/cmake/FindExceptionHandling.cmake new file mode 100644 index 000000000..b33200f2b --- /dev/null +++ b/cmake/FindExceptionHandling.cmake @@ -0,0 +1,21 @@ +if(TARGET_OS STREQUAL "windows") + set_extra_dirs_lib(EXCEPTION_HANDLING exception_handling) + find_file(EXCEPTION_HANDLING_LIBRARY + NAMES exchndl.dll + HINTS ${HINTS_EXCEPTION_HANDLING_LIBDIR} + PATHS ${PATHS_EXCEPTION_HANDLING_LIBDIR} + ${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH} + ) + + is_bundled(EXCEPTION_HANDLING_BUNDLED "${EXCEPTION_HANDLING_LIBRARY}") + if(NOT EXCEPTION_HANDLING_BUNDLED) + message(FATAL_ERROR "could not find exception handling paths") + endif() + set(EXCEPTION_HANDLING_COPY_FILES + "${EXTRA_EXCEPTION_HANDLING_LIBDIR}/exchndl.dll" + "${EXTRA_EXCEPTION_HANDLING_LIBDIR}/dbgcore.dll" + "${EXTRA_EXCEPTION_HANDLING_LIBDIR}/dbghelp.dll" + "${EXTRA_EXCEPTION_HANDLING_LIBDIR}/mgwhelp.dll" + "${EXTRA_EXCEPTION_HANDLING_LIBDIR}/symsrv.dll" + ) +endif() diff --git a/src/base/system.cpp b/src/base/system.cpp index f351b35bd..339c28065 100644 --- a/src/base/system.cpp +++ b/src/base/system.cpp @@ -4060,4 +4060,37 @@ int os_version_str(char *version, int length) return 0; #endif } + +#if defined(CONF_EXCEPTION_HANDLING) +#if defined(CONF_FAMILY_WINDOWS) +static HMODULE gs_ExceptionHandlingModule = nullptr; +#endif + +void init_exception_handler() +{ +#if defined(CONF_FAMILY_WINDOWS) + gs_ExceptionHandlingModule = LoadLibraryA("exchndl.dll"); + if(gs_ExceptionHandlingModule != nullptr) + { + auto pfnExcHndlInit = (void APIENTRY (*)())GetProcAddress(gs_ExceptionHandlingModule, "ExcHndlInit"); + pfnExcHndlInit(); + } +#else +#error exception handling not implemented +#endif +} + +void set_exception_handler_log_file(const char *pLogFilePath) +{ +#if defined(CONF_FAMILY_WINDOWS) + if(gs_ExceptionHandlingModule != nullptr) + { + auto pExceptionLogFilePathFunc = (BOOL APIENTRY(*)(const char *))(GetProcAddress(gs_ExceptionHandlingModule, "ExcHndlSetLogFileNameA")); + pExceptionLogFilePathFunc(pLogFilePath); + } +#else +#error exception handling not implemented +#endif +} +#endif } diff --git a/src/base/system.h b/src/base/system.h index 1dc8f68e2..7398b5b39 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -2368,6 +2368,11 @@ void set_console_msg_color(const void *rgbvoid); */ int os_version_str(char *version, int length); +#if defined(CONF_EXCEPTION_HANDLING) +void init_exception_handler(); +void set_exception_handler_log_file(const char *pLogFilePath); +#endif + #if defined(__cplusplus) } #endif diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index d6e3c4959..9cb5628ae 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -4268,6 +4268,10 @@ int main(int argc, const char **argv) InitAndroid(); #endif +#if defined(CONF_EXCEPTION_HANDLING) + init_exception_handler(); +#endif + if(secure_random_init() != 0) { RandInitFailed = true; @@ -4292,6 +4296,16 @@ int main(int argc, const char **argv) IDiscord *pDiscord = CreateDiscord(); ISteam *pSteam = CreateSteam(); +#if defined(CONF_EXCEPTION_HANDLING) + char aBuf[IO_MAX_PATH_LENGTH]; + char aBufName[IO_MAX_PATH_LENGTH]; + char aDate[64]; + str_timestamp(aDate, sizeof(aDate)); + str_format(aBufName, sizeof(aBufName), "dumps/" GAME_NAME "_crash_log_%d_%s.RTP", pid(), aDate); + pStorage->GetCompletePath(IStorage::TYPE_SAVE, aBufName, aBuf, sizeof(aBuf)); + set_exception_handler_log_file(aBuf); +#endif + if(RandInitFailed) { dbg_msg("secure", "could not initialize secure RNG"); diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 693161bed..89055b502 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -3645,6 +3645,10 @@ int main(int argc, const char **argv) signal(SIGINT, HandleSigIntTerm); signal(SIGTERM, HandleSigIntTerm); +#if defined(CONF_EXCEPTION_HANDLING) + init_exception_handler(); +#endif + CServer *pServer = CreateServer(); IKernel *pKernel = IKernel::Create(); @@ -3658,6 +3662,16 @@ int main(int argc, const char **argv) IConfigManager *pConfigManager = CreateConfigManager(); IEngineAntibot *pEngineAntibot = CreateEngineAntibot(); +#if defined(CONF_EXCEPTION_HANDLING) + char aBuf[IO_MAX_PATH_LENGTH]; + char aBufName[IO_MAX_PATH_LENGTH]; + char aDate[64]; + str_timestamp(aDate, sizeof(aDate)); + str_format(aBufName, sizeof(aBufName), "dumps/" GAME_NAME "-Server_crash_log_%d_%s.RTP", pid(), aDate); + pStorage->GetCompletePath(IStorage::TYPE_SAVE, aBufName, aBuf, sizeof(aBuf)); + set_exception_handler_log_file(aBuf); +#endif + pServer->InitRegister(&pServer->m_NetServer, pEngineMasterServer, pConfigManager->Values(), pConsole); { From 42373ca7a28bbc2dd5d022fcf7aed2bc4f0b3853 Mon Sep 17 00:00:00 2001 From: Dennis Felsing Date: Fri, 18 Feb 2022 11:47:15 +0100 Subject: [PATCH 2/4] exception_handling -> drmingw --- cmake/FindExceptionHandling.cmake | 2 +- ddnet-libs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/FindExceptionHandling.cmake b/cmake/FindExceptionHandling.cmake index b33200f2b..f6d12632e 100644 --- a/cmake/FindExceptionHandling.cmake +++ b/cmake/FindExceptionHandling.cmake @@ -1,5 +1,5 @@ if(TARGET_OS STREQUAL "windows") - set_extra_dirs_lib(EXCEPTION_HANDLING exception_handling) + set_extra_dirs_lib(EXCEPTION_HANDLING drmingw) find_file(EXCEPTION_HANDLING_LIBRARY NAMES exchndl.dll HINTS ${HINTS_EXCEPTION_HANDLING_LIBDIR} diff --git a/ddnet-libs b/ddnet-libs index 1cdf759f4..635aa7afb 160000 --- a/ddnet-libs +++ b/ddnet-libs @@ -1 +1 @@ -Subproject commit 1cdf759f4e46edbe174250f523b9cc737c4ad8ea +Subproject commit 635aa7afb698ed68feeb733aaea2cf861c2a1899 From a2db10d7302c8d4e663673ee9ca5480afc705960 Mon Sep 17 00:00:00 2001 From: Dennis Felsing Date: Fri, 18 Feb 2022 11:53:25 +0100 Subject: [PATCH 3/4] Set -fno-omit-frame-pointer --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 68318bb74..682b4d9b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,10 @@ if(NOT MSVC AND NOT HAIKU) if(EXCEPTION_HANDLING) add_c_compiler_flag_if_supported(OUR_FLAGS -DCONF_EXCEPTION_HANDLING) + # use the frame pointer (frame pointer usage is disabled by default in + # some architectures like x86_64 and for some optimization levels; and it + # may be impossible to walk the call stack without it) + add_c_compiler_flag_if_supported(OUR_FLAGS -fno-omit-frame-pointer) endif() add_c_compiler_flag_if_supported(OUR_FLAGS_OWN -Wall) From aaec8079637f80fa01577d1f1f724104e6649de5 Mon Sep 17 00:00:00 2001 From: Dennis Felsing Date: Fri, 18 Feb 2022 12:27:15 +0100 Subject: [PATCH 4/4] Disable invalid cast warning in set_exception_handler_log_file --- src/base/system.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/base/system.cpp b/src/base/system.cpp index 339c28065..b861256c5 100644 --- a/src/base/system.cpp +++ b/src/base/system.cpp @@ -4085,7 +4085,15 @@ void set_exception_handler_log_file(const char *pLogFilePath) #if defined(CONF_FAMILY_WINDOWS) if(gs_ExceptionHandlingModule != nullptr) { + // Intentional +#ifdef __MINGW32__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type" +#endif auto pExceptionLogFilePathFunc = (BOOL APIENTRY(*)(const char *))(GetProcAddress(gs_ExceptionHandlingModule, "ExcHndlSetLogFileNameA")); +#ifdef __MINGW32__ +#pragma clang diagnostic pop +#endif pExceptionLogFilePathFunc(pLogFilePath); } #else