From 7ba8c7f3bf16e7ab03e824cced3e55d8014b8d62 Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 19 Mar 2026 15:46:20 -0500 Subject: [PATCH] asan debug callback --- src/base/base.cgh | 15 ++++----- src/base/base_win32/base_win32.c | 52 ++++++++++++++++++++++++++------ src/base/base_win32/base_win32.h | 5 +++ src/gpu/gpu_dx12/gpu_dx12_core.c | 2 +- src/meta/meta.c | 37 ++++++++++++++++++++++- src/meta/meta.h | 1 + 6 files changed, 94 insertions(+), 18 deletions(-) diff --git a/src/base/base.cgh b/src/base/base.cgh index ac97d9c9..62e7a64d 100644 --- a/src/base/base.cgh +++ b/src/base/base.cgh @@ -176,7 +176,8 @@ #endif //- Address sanitization -#if IsAsanEnabled +#if IsAsanEnabled && IsCpu + void __asan_set_error_report_callback(void (*callback)(char *)); void __asan_poison_memory_region(void const volatile *, size_t); void __asan_unpoison_memory_region(void const volatile *, size_t); #define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size)) @@ -281,20 +282,20 @@ //////////////////////////////////////////////////////////// //~ Linked list helper macros -// Taken from the rad debugger +// Taken from the RAD Debugger // https://github.com/EpicGamesExt/raddebugger/blob/be5634c44867a2e31f6a109df5e574930992df01/src/base/base_core.h#L239 #define CheckNil(nil,p) ((p) == 0 || (p) == nil) #define SetNil(nil,p) ((p) = nil) -//- Singly linked stack (first & next pointers) +//- Singly linked stack #define SllStackPushN(f,n,next) ((n)->next=(f), (f)=(n)) #define SllStackPopN(f,next) ((f)=(f)->next) #define SllStackPush(f,n) SllStackPushN(f,n,next) #define SllStackPop(f) SllStackPopN(f,next) -//- Singly linked queue (first, last, & next pointers) +//- Singly linked queue #define SllQueuePushNZ(nil,f,l,n,next) \ ( \ @@ -324,7 +325,7 @@ #define SllQueuePopN(f,l,next) SllQueuePopNZ(0,f,l,next) #define SllQueuePop(f,l) SllQueuePopNZ(0,f,l,next) -//- Doubly linked stack (first, next, & prev pointers) +//- Doubly linked stack #define DllStackPushNPZ(nil,f,n,next,prev) \ ( \ @@ -359,7 +360,7 @@ #define DllStackRemoveNP(f,n,next,prev) DllStackRemoveNPZ(0,f,n,next,prev) #define DllStackRemove(f,n) DllStackRemoveNPZ(0,f,n,next,prev) -//- Doubly linked queue (first, last, next, & prev pointers) +//- Doubly linked queue #define DllQueueInsertNPZ(nil,f,l,p,n,next,prev) \ ( \ @@ -836,7 +837,7 @@ Inline u64 MixU64s(u64 seed_a, u64 seed_b) void LoadApi(ApiDesc api); void Echo(String msg); b32 Panic(String msg); - b32 DebugBreakPrompt(String title, String msg); + b32 DebugActionPrompt(String title, String msg); Callstack CaptureCallstack(u64 skip_frames); b32 IsRunningInDebugger(void); b32 IsRunningInWine(void); diff --git a/src/base/base_win32/base_win32.c b/src/base/base_win32/base_win32.c index e0c47929..472daca6 100644 --- a/src/base/base_win32/base_win32.c +++ b/src/base/base_win32/base_win32.c @@ -146,7 +146,7 @@ b32 Panic(String msg) return 0; } -b32 DebugBreakPrompt(String title, String msg) +b32 DebugActionPrompt(String title, String msg) { LogInfoF("[DEBUG BREAK PROMPT]: %F", FmtString(msg)); TempArena scratch = BeginScratchNoConflict(); @@ -517,19 +517,54 @@ LogEventsArray GetLogEvents(void) return result; } +//////////////////////////////////////////////////////////// +//~ Asan + +void W32_AsanCallback(char *report_cstr) +{ + i32 result = 0; + { + b32 is_debug = IsRunningInDebugger(); + i32 mb_result = 0; + { + u32 mb_flags = MB_SETFOREGROUND | MB_ICONWARNING; + if (is_debug) + { + mb_flags |= MB_CANCELTRYCONTINUE; + } + mb_result = MessageBoxExA(0, report_cstr, "Address sanitization error", mb_flags, 0); + } + if (mb_result == IDCANCEL) + { + ExitProcess(1); + } + result = is_debug && mb_result != IDCONTINUE; + } + if (result) + { + DEBUGBREAK; + } +} + //////////////////////////////////////////////////////////// //~ Main i32 W32_Main(void) { + #if IsAsanEnabled + { + __asan_set_error_report_callback(W32_AsanCallback); + } + #endif + // Init time { - LARGE_INTEGER qpf; + LARGE_INTEGER qpf = Zi; QueryPerformanceFrequency(&qpf); W32.ns_per_qpc = 1000000000 / qpf.QuadPart; } { - LARGE_INTEGER qpc; + LARGE_INTEGER qpc = Zi; QueryPerformanceCounter(&qpc); W32.timer_start_qpc = qpc.QuadPart; } @@ -552,20 +587,19 @@ i32 W32_Main(void) W32.panic_event = CreateEventW(0, 1, 0, 0); W32.exit_event = CreateEventW(0, 1, 0, 0); - W32.main_thread_id = GetCurrentThreadId(); - SetThreadDescription(GetCurrentThread(), L"Main thread"); - // Query system info GetSystemInfo(&W32.info); + // Init main thread + W32_InitCurrentThread(Lit("Main")); + W32.main_thread_id = GetCurrentThreadId(); + SetThreadDescription(GetCurrentThread(), L"Main thread"); + // Setup logging memory W32.logs_arena = AcquireArena(Gibi(64)); W32.log_events_arena = AcquireArena(Gibi(64)); W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent); - // Init main thread - W32_InitCurrentThread(Lit("Main")); - // Get raw args from command line Arena *perm = PermArena(); String cmdline_str = Zi; diff --git a/src/base/base_win32/base_win32.h b/src/base/base_win32/base_win32.h index 5e2ab51f..7a018965 100644 --- a/src/base/base_win32/base_win32.h +++ b/src/base/base_win32/base_win32.h @@ -142,6 +142,11 @@ String W32_StringFromError(Arena *arena, i32 code); void W32_LogEventToFile(LogEvent *ev, HANDLE file); void W32_Log(i32 level, String msg); +//////////////////////////////////////////////////////////// +//~ Asan + +void W32_AsanCallback(char *report_cstr); + //////////////////////////////////////////////////////////// //~ Main diff --git a/src/gpu/gpu_dx12/gpu_dx12_core.c b/src/gpu/gpu_dx12/gpu_dx12_core.c index ab3e2243..b094f99a 100644 --- a/src/gpu/gpu_dx12/gpu_dx12_core.c +++ b/src/gpu/gpu_dx12/gpu_dx12_core.c @@ -4008,7 +4008,7 @@ void G_D12_DebugCallback( { String description = StringFromCstrNoLimit((char *)description_cstr); Echo(StringF(scratch.arena, "[D3D12 DEBUG] %F\n", FmtString(description))); - if (DebugBreakPrompt(Lit("D3D12 Debug Break"), description)) + if (DebugActionPrompt(Lit("D3D12 Debug Break"), description)) { DEBUGBREAK; } diff --git a/src/meta/meta.c b/src/meta/meta.c index def3ba16..1973e79d 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -405,6 +405,15 @@ void M_BuildEntryPoint(WaveLaneCtx *lane) } } + // Asan + { + CommandlineArg arg = CommandlineArgFromName(Lit("asan")); + if (arg.exists) + { + M.cmdline.asan = 1; + } + } + if (lane->idx == 0) { if (M.cmdline.target_compiler == M_CompilerKind_Msvc) @@ -425,6 +434,11 @@ void M_BuildEntryPoint(WaveLaneCtx *lane) M_EchoLine(Lit("[Debug build]")); } + if (M.cmdline.asan) + { + M_EchoLine(Lit("[ASAN]")); + } + M_EchoLine(StringF(perm, "Building layer \"%F\"", FmtString(M.cmdline.leaf_layer_name))); } @@ -455,7 +469,15 @@ void M_BuildEntryPoint(WaveLaneCtx *lane) PushStringToList(perm, &cp.defs, Lit("-DIsConsoleApp=0")); } - PushStringToList(perm, &cp.defs, Lit("-DIsAsanEnabled=0")); + if (M.cmdline.asan) + { + PushStringToList(perm, &cp.defs, Lit("-DIsAsanEnabled=1")); + } + else + { + PushStringToList(perm, &cp.defs, Lit("-DIsAsanEnabled=0")); + } + PushStringToList(perm, &cp.defs, Lit("-DIsDebinfoEnabled=1")); PushStringToList(perm, &cp.defs, Lit("-DIsDeveloperModeEnabled=1")); PushStringToList(perm, &cp.defs, Lit("-DIsTestingEnabled=0")); @@ -481,6 +503,19 @@ void M_BuildEntryPoint(WaveLaneCtx *lane) PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Od")); } + if (M.cmdline.asan) + { + PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-fsanitize=address")); + // PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-fsanitize-address-use-after-return")); + } + else + { + if (!M.cmdline.release) + { + PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-RTCsu")); + } + } + // TODO: Export debug info separately for release builds PushStringToList(perm, &cp.flags_msvc, Lit("-DEBUG:FULL")); PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Z7")); diff --git a/src/meta/meta.h b/src/meta/meta.h index 0344c58c..d9e36d24 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -141,6 +141,7 @@ Struct(M_CommandLine) { b32 release; b32 console; + b32 asan; String leaf_layer_name; M_PlatformKind target_platform; M_CompilerKind target_compiler;