// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team // SPDX-License-Identifier: GPL-3.0+ #include "Assertions.h" #include "CrashHandler.h" #include "HostSys.h" #include "Threading.h" #include #include "fmt/core.h" #ifdef _WIN32 #include "RedtapeWindows.h" #include #include #endif #ifdef __UNIX__ #include #endif static std::mutex s_assertion_failed_mutex; static inline void FreezeThreads(void** handle) { #if defined(_WIN32) HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (snapshot != INVALID_HANDLE_VALUE) { THREADENTRY32 threadEntry; if (Thread32First(snapshot, &threadEntry)) { do { if (threadEntry.th32ThreadID == GetCurrentThreadId()) continue; HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadEntry.th32ThreadID); if (hThread != nullptr) { SuspendThread(hThread); CloseHandle(hThread); } } while (Thread32Next(snapshot, &threadEntry)); } } *handle = static_cast(snapshot); #else * handle = nullptr; #endif } static inline void ResumeThreads(void* handle) { #if defined(_WIN32) if (handle != INVALID_HANDLE_VALUE) { THREADENTRY32 threadEntry; if (Thread32First(reinterpret_cast(handle), &threadEntry)) { do { if (threadEntry.th32ThreadID == GetCurrentThreadId()) continue; HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadEntry.th32ThreadID); if (hThread != nullptr) { ResumeThread(hThread); CloseHandle(hThread); } } while (Thread32Next(reinterpret_cast(handle), &threadEntry)); } CloseHandle(reinterpret_cast(handle)); } #else #endif } void pxOnAssertFail(const char* file, int line, const char* func, const char* msg) { std::unique_lock guard(s_assertion_failed_mutex); void* handle; FreezeThreads(&handle); char full_msg[512]; std::snprintf(full_msg, sizeof(full_msg), "%s:%d: assertion failed in function %s: %s\n", file, line, func, msg); #if defined(_WIN32) HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE); if (error_handle != INVALID_HANDLE_VALUE) WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), full_msg, static_cast(std::strlen(full_msg)), NULL, NULL); OutputDebugStringA(full_msg); std::snprintf( full_msg, sizeof(full_msg), "Assertion failed in function %s (%s:%d):\n\n%s\n\nPress Abort to exit, Retry to break to debugger, or Ignore to attempt to continue.", func, file, line, msg); int result = MessageBoxA(NULL, full_msg, NULL, MB_ABORTRETRYIGNORE | MB_ICONERROR); if (result == IDRETRY) { __debugbreak(); } else if (result != IDIGNORE) { // try to save a crash dump before exiting CrashHandler::WriteDumpForCaller(); TerminateProcess(GetCurrentProcess(), 0xBAADC0DE); } #else fputs(full_msg, stderr); fputs("\nAborting application.\n", stderr); fflush(stderr); AbortWithMessage(full_msg); #endif ResumeThreads(handle); }