4729: Add exception handling for Windows r=def- a=Jupeyy

Only tested on wine yet.

I am using https://github.com/jrfonseca/drmingw

We don't need to ship debug symbols, but need to keep a copy of DDNet.exe with debug symbols. Using addr2line works on the addresses printed by this tool.

currently crash reports go into %appdata%/Teeworlds/dumps (that dir seems to be rarely used anyway, but can also change to /crashlogs or smth)



## Checklist

- [ ] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test if it works standalone, system.c especially
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Jupeyy <jupjopjap@gmail.com>
Co-authored-by: Dennis Felsing <dennis@felsin9.de>
This commit is contained in:
bors[bot] 2022-02-18 13:51:58 +00:00 committed by GitHub
commit b793e1e41b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 117 additions and 1 deletions

View file

@ -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,14 @@ 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)
# 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)
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 +249,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 +456,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 +1419,7 @@ set(COPY_FILES
${FFMPEG_COPY_FILES}
${WEBSOCKETS_COPY_FILES}
${DISCORDSDK_COPY_FILES}
${EXCEPTION_HANDLING_COPY_FILES}
)
file(COPY ${COPY_FILES} DESTINATION .)

View file

@ -0,0 +1,21 @@
if(TARGET_OS STREQUAL "windows")
set_extra_dirs_lib(EXCEPTION_HANDLING drmingw)
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()

@ -1 +1 @@
Subproject commit 1cdf759f4e46edbe174250f523b9cc737c4ad8ea
Subproject commit 635aa7afb698ed68feeb733aaea2cf861c2a1899

View file

@ -4060,4 +4060,45 @@ 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)
{
// 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
#error exception handling not implemented
#endif
}
#endif
}

View file

@ -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

View file

@ -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");

View file

@ -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);
{