Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/common/assert.cpp
7326 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#if !defined(__APPLE__) && !defined(__ANDROID__)
5
6
#include "assert.h"
7
#include "crash_handler.h"
8
9
#include <cstdio>
10
#include <cstdlib>
11
12
#ifdef _WIN32
13
14
#include "windows_headers.h"
15
#include <intrin.h>
16
#include <tlhelp32.h>
17
18
#include <mutex>
19
20
#ifdef __clang__
21
#pragma clang diagnostic ignored "-Winvalid-noreturn"
22
#endif
23
24
static std::mutex s_AssertFailedMutex;
25
26
static HANDLE FreezeThreads()
27
{
28
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
29
if (hSnapshot != INVALID_HANDLE_VALUE)
30
{
31
THREADENTRY32 threadEntry;
32
if (Thread32First(hSnapshot, &threadEntry))
33
{
34
do
35
{
36
if (threadEntry.th32ThreadID == GetCurrentThreadId())
37
continue;
38
39
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadEntry.th32ThreadID);
40
if (hThread != NULL)
41
{
42
SuspendThread(hThread);
43
CloseHandle(hThread);
44
}
45
} while (Thread32Next(hSnapshot, &threadEntry));
46
}
47
}
48
49
return hSnapshot;
50
}
51
52
static void ResumeThreads(HANDLE hSnapshot)
53
{
54
if (hSnapshot != INVALID_HANDLE_VALUE)
55
{
56
THREADENTRY32 threadEntry;
57
if (Thread32First(hSnapshot, &threadEntry))
58
{
59
do
60
{
61
if (threadEntry.th32ThreadID == GetCurrentThreadId())
62
continue;
63
64
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadEntry.th32ThreadID);
65
if (hThread != NULL)
66
{
67
ResumeThread(hThread);
68
CloseHandle(hThread);
69
}
70
} while (Thread32Next(hSnapshot, &threadEntry));
71
}
72
CloseHandle(hSnapshot);
73
}
74
}
75
76
#endif // _WIN32
77
78
void Y_OnAssertFailed(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
79
{
80
char szMsg[512];
81
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine);
82
83
#if defined(_WIN32)
84
std::unique_lock lock(s_AssertFailedMutex);
85
HANDLE pHandle = FreezeThreads();
86
87
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
88
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast<DWORD>(std::strlen(szMsg)), NULL, NULL);
89
OutputDebugStringA(szMsg);
90
91
std::snprintf(
92
szMsg, sizeof(szMsg),
93
"%s in function %s (%s:%u)\nPress Abort to exit, Retry to break to debugger, or Ignore to attempt to continue.",
94
szMessage, szFunction, szFile, uLine);
95
96
int result = MessageBoxA(NULL, szMsg, NULL, MB_ABORTRETRYIGNORE | MB_ICONERROR);
97
if (result == IDRETRY)
98
{
99
__debugbreak();
100
}
101
else if (result != IDIGNORE)
102
{
103
CrashHandler::WriteDumpForCaller(szMsg);
104
TerminateProcess(GetCurrentProcess(), 0xBAADC0DE);
105
}
106
107
ResumeThreads(pHandle);
108
#else
109
std::fputs(szMsg, stderr);
110
std::fflush(stderr);
111
std::abort();
112
#endif
113
}
114
115
[[noreturn]] void Y_OnPanicReached(const char* szMessage, const char* szFunction, const char* szFile, unsigned uLine)
116
{
117
char szMsg[512];
118
std::snprintf(szMsg, sizeof(szMsg), "%s in function %s (%s:%u)\n", szMessage, szFunction, szFile, uLine);
119
120
#if defined(_WIN32)
121
std::unique_lock guard(s_AssertFailedMutex);
122
HANDLE pHandle = FreezeThreads();
123
124
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
125
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), szMsg, static_cast<DWORD>(std::strlen(szMsg)), NULL, NULL);
126
OutputDebugStringA(szMsg);
127
128
std::snprintf(szMsg, sizeof(szMsg),
129
"%s in function %s (%s:%u)\nDo you want to attempt to break into a debugger? Pressing Cancel will "
130
"abort the application.",
131
szMessage, szFunction, szFile, uLine);
132
133
int result = MessageBoxA(NULL, szMsg, NULL, MB_OKCANCEL | MB_ICONERROR);
134
if (result == IDOK)
135
__debugbreak();
136
else
137
CrashHandler::WriteDumpForCaller(szMsg);
138
139
TerminateProcess(GetCurrentProcess(), 0xBAADC0DE);
140
141
ResumeThreads(pHandle);
142
#else
143
std::fputs(szMsg, stderr);
144
std::fflush(stderr);
145
std::abort();
146
#endif
147
}
148
149
#endif // !defined(__APPLE__) && !defined(__ANDROID__)
150
151