Skip to content

Commit 8c1b074

Browse files
feat: crash handler implementation for windows
1 parent 2b7473a commit 8c1b074

6 files changed

Lines changed: 618 additions & 10 deletions

File tree

Obelisk/EntryPoint.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <Tetragrama/Editor.h>
33
#include <ZEngine/Applications/GameApplication.h>
44
#include <ZEngine/Core/Memory/MemoryManager.h>
5+
#include <ZEngine/CrashHandlers/CrashHandler.h>
56
#include <ZEngine/EngineConfiguration.h>
67
#include <ZEngine/Helpers/ThreadPool.h>
78
#include <ZEngine/Logging/Logger.h>
@@ -12,9 +13,12 @@ using namespace ZEngine;
1213
using namespace ZEngine::Logging;
1314
using namespace ZEngine::Core::Memory;
1415
using namespace ZEngine::Applications;
16+
using namespace ZEngine::CrashHandlers;
1517

1618
int applicationEntryPoint(int argc, char* argv[])
1719
{
20+
CrashHandler::Install("Obelisk", "1.0.0", "CrashDumps");
21+
1822
MemoryManager manager = {};
1923
MemoryConfiguration config = {.BufferSize = ZGiga(3u)};
2024
manager.Initialize(config);
@@ -43,7 +47,10 @@ int applicationEntryPoint(int argc, char* argv[])
4347
app->EnableRenderOverlay = true;
4448
}
4549

46-
app->ConfigFile = config_file.c_str();
50+
auto config_file_str_size = config_file.size() + 1;
51+
auto config_file_str = ZPushString(arena, config_file_str_size);
52+
Helpers::secure_strncpy(config_file_str, config_file_str_size, config_file.c_str(), config_file.size());
53+
app->ConfigFile = config_file_str;
4754

4855
app->Initialize(arena);
4956
app->Run();
@@ -53,6 +60,7 @@ int applicationEntryPoint(int argc, char* argv[])
5360

5461
manager.Shutdown();
5562

63+
CrashHandler::Uninstall();
5664
return 0;
5765
}
5866

ZEngine/ZEngine/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ target_include_directories (zEngineLib
8484
./Windows/Layers
8585
./Managers
8686
./Serializers
87+
# Idealy we want to convert this to modules/extensions
88+
#
89+
./CrashHandlers
8790
)
8891

8992
target_precompile_headers(zEngineLib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/pch.h)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#pragma once
2+
3+
namespace ZEngine::CrashHandlers
4+
{
5+
struct CrashHandler
6+
{
7+
using PreCrashFn = void (*)(void* ctx);
8+
using cstring = const char*;
9+
10+
// Install the platform crash handler.
11+
// app_name — e.g. "GameName"
12+
// version — e.g. "1.0.0"
13+
// crash_log_dir — directory where crash logs and .dmp files are written.
14+
// Created if it does not exist.
15+
//
16+
// Call once, before any engine subsystem is initialized.
17+
// No-op if already installed.
18+
static void Install(cstring app_name, cstring version, cstring crash_log_dir);
19+
20+
// Remove the platform crash handler and restore default OS behavior.
21+
// Call at engine shutdown. Safe to call if Install() was never called.
22+
static void Uninstall();
23+
24+
// Set a callback to be called just before the crash dump is written.
25+
// This is useful for flushing logs, saving game state, etc.
26+
//
27+
// The callback must complete within a defined timeout (default 2 seconds) or the crash handler will proceed to write the dump anyway.
28+
// On Windows, a helper thread's timeout fires
29+
// On Linux, macOS SIGALRM is raised on the callback thread
30+
//
31+
// Only one callback can be set at a time. Setting a new callback replaces the previous one.
32+
// It must not allocate memory on the ZEngine heap, or call ZENGINE_VALIDATE_ASSERT.
33+
static void SetPreCrashCallback(PreCrashFn fn, void* ctx = nullptr);
34+
35+
// Called by the platform handler (SEH filter on Windows, signal handler
36+
// on POSIX) to perform the cross-platform crash response.
37+
// signal_or_exception — human-readable description, e.g.
38+
// "Access Violation at 0x0000000000000000"
39+
// context — platform-specific context:
40+
// Windows: EXCEPTION_POINTERS*
41+
// POSIX: ucontext_t*
42+
//
43+
// This function does not return under normal conditions.
44+
[[noreturn]] static void OnCrash(cstring signal_or_exception, void* ctx = nullptr);
45+
46+
// Called by ZENGINE_VALIDATE_ASSERT to produce a crash report for
47+
// assertion failures in Release/RelWithDebInfo builds.
48+
// file — __FILE__
49+
// line — __LINE__
50+
// message — the assertion condition and user message string
51+
[[noreturn]] static void OnAssertionFailure(cstring file, int line, cstring message);
52+
53+
private:
54+
CrashHandler() = delete;
55+
56+
static void StoreMetadata(cstring app_name, cstring version, cstring crash_log_dir);
57+
};
58+
} // namespace ZEngine::CrashHandlers
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
#include <CrashHandlers/CrashHandler.h>
3+
4+
namespace ZEngine::CrashHandlers
5+
{
6+
namespace
7+
{
8+
constexpr size_t kMaxPathLen = 512;
9+
constexpr size_t kMaxTraceLen = 8192;
10+
constexpr size_t kMaxNameLen = 128;
11+
constexpr int kCallbackTimeoutSec = 2;
12+
13+
struct CrashHandlerState
14+
{
15+
bool Installed = false;
16+
bool UserConsentUpload = false;
17+
char AppName[kMaxNameLen] = {};
18+
char Version[kMaxNameLen] = {};
19+
char CrashLogDir[kMaxPathLen] = {};
20+
21+
void* PreCrashCtx = nullptr;
22+
CrashHandler::PreCrashFn PreCrashFn = nullptr;
23+
};
24+
25+
static CrashHandlerState g_state;
26+
} // namespace
27+
} // namespace ZEngine::CrashHandlers

0 commit comments

Comments
 (0)