Skip to content

Commit 4f496fe

Browse files
committed
test crash handler
1 parent d0d0f2e commit 4f496fe

7 files changed

Lines changed: 227 additions & 37 deletions

File tree

.github/workflows/tests.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ jobs:
5151
cd build/result/${{ matrix.build-config }}
5252
./cage-test-core
5353
54+
- name: Crash handler
55+
shell: bash
56+
run: |
57+
cd build/result/${{ matrix.build-config }}
58+
./cage-test-crash write-to-null || true
59+
echo "log:"
60+
cat cage-test-crash.log
61+
5462
- name: Assets
5563
shell: bash
5664
run: |
@@ -127,6 +135,14 @@ jobs:
127135
cd build/result/${{ matrix.build-config }}
128136
./cage-test-core
129137
138+
- name: Crash handler
139+
shell: bash
140+
run: |
141+
cd build/result/${{ matrix.build-config }}
142+
./cage-test-crash write-to-null || true
143+
echo "log:"
144+
cat cage-test-crash.log
145+
130146
- name: Assets
131147
run: |
132148
cd build/result/${{ matrix.build-config }}
@@ -180,6 +196,14 @@ jobs:
180196
cd build/result/${{ matrix.build-config }}
181197
./cage-test-core
182198
199+
- name: Crash handler
200+
shell: bash
201+
run: |
202+
cd build/result/${{ matrix.build-config }}
203+
./cage-test-crash write-to-null || true
204+
echo "log:"
205+
cat cage-test-crash.log
206+
183207
- name: Assets
184208
run: |
185209
cd build/result/${{ matrix.build-config }}

sources/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,13 @@ cage_ide_category(cage-test-entities cage/tests)
173173
cage_ide_sort_files(cage-test-entities)
174174
cage_ide_working_dir_in_place(cage-test-entities)
175175

176+
file(GLOB_RECURSE cage-test-crash-sources "test-crash/*")
177+
add_executable(cage-test-crash ${cage-test-crash-sources})
178+
target_link_libraries(cage-test-crash cage-core)
179+
cage_ide_category(cage-test-crash cage/tests)
180+
cage_ide_sort_files(cage-test-crash)
181+
cage_ide_working_dir_in_place(cage-test-crash)
182+
176183
########
177184
# TOOLS
178185
########

sources/libcore/errors/crashHandlerSignals.cpp

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,29 @@ namespace cage
3434
}
3535
}
3636

37+
void crashHandlerPrintThread()
38+
{
39+
privat::crashHandlerSafeWrite(Stringizer() + "in thread: " + currentThreadName() + "\n");
40+
}
41+
42+
void crashHandlerPrintStack()
43+
{
44+
// backtrace (best-effort; not strictly async-signal-safe)
45+
static constexpr int MaxFrames = 256;
46+
void *frames[MaxFrames];
47+
int n = backtrace(frames, MaxFrames);
48+
if (n <= 0)
49+
{
50+
crashHandlerSafeWrite("stack trace: <empty>\n");
51+
return;
52+
}
53+
crashHandlerSafeWrite(Stringizer() + "stack trace:\n");
54+
backtrace_symbols_fd(frames, n, crashHandlerLogFileFd);
55+
if (crashHandlerLogFileFd != STDERR_FILENO)
56+
backtrace_symbols_fd(frames, n, STDERR_FILENO);
57+
crashHandlerSafeWrite("\n");
58+
}
59+
3760
void crashHandlerThreadInit()
3861
{
3962
// install alternative stack memory for handling signals
@@ -80,6 +103,7 @@ namespace cage
80103
return &prevHandlers[sig];
81104
return nullptr;
82105
}
106+
83107
const char *sigToStr(int sig)
84108
{
85109
switch (sig)
@@ -189,19 +213,6 @@ namespace cage
189213
}
190214
}
191215

192-
void printStackTrace()
193-
{
194-
// backtrace (best-effort; not strictly async-signal-safe)
195-
static constexpr int MaxFrames = 256;
196-
void *frames[MaxFrames];
197-
int n = backtrace(frames, MaxFrames);
198-
privat::crashHandlerSafeWrite(Stringizer() + "stack trace:\n");
199-
backtrace_symbols_fd(frames, n, privat::crashHandlerLogFileFd);
200-
if (privat::crashHandlerLogFileFd != STDERR_FILENO)
201-
backtrace_symbols_fd(frames, n, STDERR_FILENO);
202-
privat::crashHandlerSafeWrite("\n");
203-
}
204-
205216
void performPreviousHandler(int sig, siginfo_t *si, void *uctx)
206217
{
207218
if (struct sigaction *prev = prevHandler(sig))
@@ -230,8 +241,8 @@ namespace cage
230241
privat::crashHandlerSafeWrite(Stringizer() + "signal handler: " + sigToStr(sig) + " (" + sig + ")\n");
231242
if (si)
232243
privat::crashHandlerSafeWrite(Stringizer() + "fault addr: " + (uintptr_t)si->si_addr + ", code: " + si->si_code + "\n");
233-
privat::crashHandlerSafeWrite(Stringizer() + "in thread: " + currentThreadName() + "\n");
234-
printStackTrace();
244+
privat::crashHandlerPrintThread();
245+
privat::crashHandlerPrintStack();
235246
performPreviousHandler(sig, si, uctx);
236247
}
237248

sources/libcore/errors/crashHandlerWindows.cpp

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,30 @@
1717

1818
namespace cage
1919
{
20+
namespace
21+
{
22+
void printStackTrace(PEXCEPTION_POINTERS ex);
23+
}
24+
2025
namespace privat
2126
{
27+
void crashHandlerPrintThread()
28+
{
29+
CAGE_LOG(SeverityEnum::Info, "crash-handler", Stringizer() + "in thread: " + currentThreadName());
30+
}
31+
32+
void crashHandlerPrintStack()
33+
{
34+
CONTEXT ctx = {};
35+
RtlCaptureContext(&ctx); // manual context capture
36+
EXCEPTION_RECORD rec = {};
37+
rec.ExceptionCode = 0xDEAD; // custom marker
38+
EXCEPTION_POINTERS ptrs = {};
39+
ptrs.ContextRecord = &ctx;
40+
ptrs.ExceptionRecord = &rec;
41+
printStackTrace(&ptrs);
42+
}
43+
2244
void crashHandlerThreadInit()
2345
{
2446
// reserve safe memory on the stack for handling EXCEPTION_STACK_OVERFLOW
@@ -222,10 +244,11 @@ namespace cage
222244
str + symbol->Name;
223245
}
224246
CAGE_LOG_CONTINUE(SeverityEnum::Info, "crash-handler", str.value.empty() ? String("unknown-frame") : str);
225-
if (++iteration == 50)
247+
if (++iteration >= 100)
226248
break;
227249
}
228250
SymCleanup(process);
251+
CAGE_LOG_CONTINUE(SeverityEnum::Info, "crash-handler", "");
229252
}
230253
else
231254
{
@@ -259,7 +282,7 @@ namespace cage
259282
for (uint32 i = 0; i < ex->ExceptionRecord->NumberParameters; i++)
260283
CAGE_LOG(SeverityEnum::Info, "crash-handler", Stringizer() + "parameter[" + i + "]: " + ex->ExceptionRecord->ExceptionInformation);
261284
}
262-
CAGE_LOG(SeverityEnum::Info, "crash-handler", Stringizer() + "in thread: " + currentThreadName());
285+
privat::crashHandlerPrintThread();
263286
printStackTrace(ex);
264287
}
265288

@@ -276,7 +299,10 @@ namespace cage
276299
{
277300
commonHandler(ex);
278301
if (previousExceptionFilter)
302+
{
303+
CAGE_LOG(SeverityEnum::Info, "crash-handler", "calling previous handler");
279304
return previousExceptionFilter(ex);
305+
}
280306
return EXCEPTION_CONTINUE_SEARCH;
281307
}
282308

@@ -301,37 +327,31 @@ namespace cage
301327
return data;
302328
}
303329

304-
_invalid_parameter_handler previousInvalidParameter = nullptr;
330+
void commonHandler()
331+
{
332+
privat::crashHandlerPrintThread();
333+
privat::crashHandlerPrintStack();
334+
CAGE_LOG(SeverityEnum::Info, "crash-handler", "calling abort");
335+
std::abort();
336+
}
305337

306338
void invalidParameterHandler(const wchar_t *expression, const wchar_t *function, const wchar_t *file, unsigned int line, uintptr_t pReserved)
307339
{
308340
CAGE_LOG(SeverityEnum::Error, "crash-handler", "crash handler: invalid parameter");
309341
CAGE_LOG(SeverityEnum::Info, "crash-handler", Stringizer() + "expression: " + narrow(expression) + ", function: " + narrow(function));
310-
CAGE_LOG(SeverityEnum::Info, "crash-handler", Stringizer() + "in thread: " + currentThreadName());
311-
detail::debugBreakpoint();
312-
if (previousInvalidParameter)
313-
previousInvalidParameter(expression, function, file, line, pReserved);
314-
std::terminate();
342+
commonHandler();
315343
}
316344

317-
_purecall_handler previousPurecall = nullptr;
318-
319345
void purecallHandler()
320346
{
321347
CAGE_LOG(SeverityEnum::Error, "crash-handler", "crash handler: purecall");
322-
CAGE_LOG(SeverityEnum::Info, "crash-handler", Stringizer() + "in thread: " + currentThreadName());
323-
detail::debugBreakpoint();
324-
if (previousPurecall)
325-
previousPurecall();
326-
std::terminate();
348+
commonHandler();
327349
}
328350

329351
void sigAbrtHandler(int)
330352
{
331353
CAGE_LOG(SeverityEnum::Error, "crash-handler", "crash handler: abort signal");
332-
CAGE_LOG(SeverityEnum::Info, "crash-handler", Stringizer() + "in thread: " + currentThreadName());
333-
detail::debugBreakpoint();
334-
std::terminate();
354+
commonHandler();
335355
}
336356

337357
struct SetupHandlersWindows
@@ -347,8 +367,8 @@ namespace cage
347367
previousExceptionFilter = SetUnhandledExceptionFilter(&unhandledHandler);
348368
if (!SetConsoleCtrlHandler(&consoleHandler, TRUE))
349369
CAGE_THROW_ERROR(SystemError, "SetConsoleCtrlHandler", GetLastError());
350-
previousInvalidParameter = _set_invalid_parameter_handler(&invalidParameterHandler);
351-
previousPurecall = _set_purecall_handler(&purecallHandler);
370+
_set_invalid_parameter_handler(&invalidParameterHandler);
371+
_set_purecall_handler(&purecallHandler);
352372
signal(SIGABRT, &sigAbrtHandler);
353373
}
354374
} setupHandlersWindows;

sources/libcore/errors/debug.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,19 @@ static_assert(CAGE_DEBUG_BOOL == false);
3232

3333
namespace cage
3434
{
35+
namespace privat
36+
{
37+
void crashHandlerPrintThread();
38+
void crashHandlerPrintStack();
39+
}
40+
3541
namespace
3642
{
3743
std::terminate_handler previousTerminateHandler;
3844

3945
[[noreturn]] void terminateHandler()
4046
{
41-
CAGE_LOG(SeverityEnum::Critical, "terminate", "terminate handler was invoked");
47+
CAGE_LOG(SeverityEnum::Critical, "terminate", "terminate handler is invoked");
4248
try
4349
{
4450
if (std::exception_ptr eptr = std::current_exception())
@@ -48,8 +54,13 @@ namespace cage
4854
{
4955
detail::logCurrentCaughtException();
5056
}
57+
privat::crashHandlerPrintThread();
58+
privat::crashHandlerPrintStack();
5159
detail::debugBreakpoint();
52-
previousTerminateHandler();
60+
//CAGE_LOG(SeverityEnum::Info, "terminate", "calling previous terminate handler");
61+
//previousTerminateHandler();
62+
CAGE_LOG(SeverityEnum::Info, "terminate", "calling abort");
63+
std::abort();
5364
throw;
5465
}
5566

0 commit comments

Comments
 (0)