From 7f3687de810e8c701eab93cccb73be3041d0c540 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 8 Dec 2024 02:56:40 +1000 Subject: [PATCH] Common: Report assertion failure/panic message for Android --- src/common/assert.cpp | 81 ++++++++++++++++++++---------------- src/common/assert.h | 28 +++++++------ src/common/crash_handler.cpp | 2 +- 3 files changed, 61 insertions(+), 50 deletions(-) diff --git a/src/common/assert.cpp b/src/common/assert.cpp index 9c39c8ba9..6c116b469 100644 --- a/src/common/assert.cpp +++ b/src/common/assert.cpp @@ -3,15 +3,17 @@ #include "assert.h" #include "crash_handler.h" + #include #include -#include -#if defined(_WIN32) +#ifdef _WIN32 + #include "windows_headers.h" #include #include -#endif + +#include #ifdef __clang__ #pragma clang diagnostic ignored "-Winvalid-noreturn" @@ -19,9 +21,8 @@ static std::mutex s_AssertFailedMutex; -static inline void FreezeThreads(void** ppHandle) +static HANDLE FreezeThreads() { -#if defined(_WIN32) HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hSnapshot != INVALID_HANDLE_VALUE) { @@ -43,17 +44,12 @@ static inline void FreezeThreads(void** ppHandle) } } - *ppHandle = (void*)hSnapshot; -#else - *ppHandle = nullptr; -#endif + return hSnapshot; } -static inline void ResumeThreads(void* pHandle) +static void ResumeThreads(HANDLE hSnapshot) { -#if defined(_WIN32) - HANDLE hSnapshot = (HANDLE)pHandle; - if (pHandle != INVALID_HANDLE_VALUE) + if (hSnapshot != INVALID_HANDLE_VALUE) { THREADENTRY32 threadEntry; if (Thread32First(hSnapshot, &threadEntry)) @@ -73,21 +69,42 @@ static inline void ResumeThreads(void* pHandle) } CloseHandle(hSnapshot); } +} + #else + +#ifdef __ANDROID__ +// Define as a weak symbol for ancient devices that don't have it. +extern "C" __attribute__((weak)) void android_set_abort_message(const char*); +#endif + +[[noreturn]] ALWAYS_INLINE static void AbortWithMessage(const char* szMsg) +{ +#ifndef __ANDROID__ + std::fputs(szMsg, stderr); + CrashHandler::WriteDumpForCaller(); + std::fputs("Aborting application.\n", stderr); + std::fflush(stderr); + std::abort(); +#else + if (&android_set_abort_message) + android_set_abort_message(szMsg); + + std::abort(); #endif } +#endif // _WIN32 + void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine) { - std::lock_guard guard(s_AssertFailedMutex); - - void* pHandle; - FreezeThreads(&pHandle); - char szMsg[512]; std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine); #if defined(_WIN32) + std::unique_lock lock(s_AssertFailedMutex); + HANDLE pHandle = FreezeThreads(); + SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY); WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast(std::strlen(szMsg)), NULL, NULL); OutputDebugStringA(szMsg); @@ -107,28 +124,22 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* CrashHandler::WriteDumpForCaller(); TerminateProcess(GetCurrentProcess(), 0xBAADC0DE); } -#else - std::fputs(szMsg, stderr); - CrashHandler::WriteDumpForCaller(); - std::fputs("Aborting application.\n", stderr); - std::fflush(stderr); - std::abort(); -#endif ResumeThreads(pHandle); +#else + AbortWithMessage(szMsg); +#endif } [[noreturn]] void Y_OnPanicReached(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine) { - std::lock_guard guard(s_AssertFailedMutex); - - void* pHandle; - FreezeThreads(&pHandle); - char szMsg[512]; std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine); #if defined(_WIN32) + std::unique_lock guard(s_AssertFailedMutex); + HANDLE pHandle = FreezeThreads(); + SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY); WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast(std::strlen(szMsg)), NULL, NULL); OutputDebugStringA(szMsg); @@ -145,13 +156,9 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* CrashHandler::WriteDumpForCaller(); TerminateProcess(GetCurrentProcess(), 0xBAADC0DE); -#else - std::fputs(szMsg, stderr); - CrashHandler::WriteDumpForCaller(); - std::fputs("Aborting application.\n", stderr); - std::fflush(stderr); - std::abort(); -#endif ResumeThreads(pHandle); +#else + AbortWithMessage(szMsg); +#endif } diff --git a/src/common/assert.h b/src/common/assert.h index fd7d4d884..2578f3fa1 100644 --- a/src/common/assert.h +++ b/src/common/assert.h @@ -9,27 +9,31 @@ void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* [[noreturn]] void Y_OnPanicReached(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine); #define Assert(expr) \ - if (!(expr)) \ + do \ { \ - Y_OnAssertFailed("Assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \ - } + if (!(expr)) \ + Y_OnAssertFailed("Assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \ + } while (0) #define AssertMsg(expr, msg) \ - if (!(expr)) \ + do \ { \ - Y_OnAssertFailed("Assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \ - } + if (!(expr)) \ + Y_OnAssertFailed("Assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \ + } while (0) #if defined(_DEBUG) || defined(_DEVEL) #define DebugAssert(expr) \ - if (!(expr)) \ + do \ { \ - Y_OnAssertFailed("Debug assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \ - } + if (!(expr)) \ + Y_OnAssertFailed("Debug assertion failed: '" #expr "'", __FUNCTION__, __FILE__, __LINE__); \ + } while (0) #define DebugAssertMsg(expr, msg) \ - if (!(expr)) \ + do \ { \ - Y_OnAssertFailed("Debug assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \ - } + if (!(expr)) \ + Y_OnAssertFailed("Debug assertion failed: '" msg "'", __FUNCTION__, __FILE__, __LINE__); \ + } while (0) #else #define DebugAssert(expr) #define DebugAssertMsg(expr, msg) diff --git a/src/common/crash_handler.cpp b/src/common/crash_handler.cpp index 724427446..a432791b5 100644 --- a/src/common/crash_handler.cpp +++ b/src/common/crash_handler.cpp @@ -367,7 +367,7 @@ void CrashHandler::WriteDumpForCaller() LogCallstack(0, nullptr); } -#else +#elif !defined(__ANDROID__) bool CrashHandler::Install(CleanupHandler cleanup_handler) {