asan debug callback

This commit is contained in:
jacob 2026-03-19 15:46:20 -05:00
parent 3d110a1da5
commit 7ba8c7f3bf
6 changed files with 94 additions and 18 deletions

View File

@ -176,7 +176,8 @@
#endif #endif
//- Address sanitization //- 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_poison_memory_region(void const volatile *, size_t);
void __asan_unpoison_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)) #define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size))
@ -281,20 +282,20 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Linked list helper macros //~ 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 // https://github.com/EpicGamesExt/raddebugger/blob/be5634c44867a2e31f6a109df5e574930992df01/src/base/base_core.h#L239
#define CheckNil(nil,p) ((p) == 0 || (p) == nil) #define CheckNil(nil,p) ((p) == 0 || (p) == nil)
#define SetNil(nil,p) ((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 SllStackPushN(f,n,next) ((n)->next=(f), (f)=(n))
#define SllStackPopN(f,next) ((f)=(f)->next) #define SllStackPopN(f,next) ((f)=(f)->next)
#define SllStackPush(f,n) SllStackPushN(f,n,next) #define SllStackPush(f,n) SllStackPushN(f,n,next)
#define SllStackPop(f) SllStackPopN(f,next) #define SllStackPop(f) SllStackPopN(f,next)
//- Singly linked queue (first, last, & next pointers) //- Singly linked queue
#define SllQueuePushNZ(nil,f,l,n,next) \ #define SllQueuePushNZ(nil,f,l,n,next) \
( \ ( \
@ -324,7 +325,7 @@
#define SllQueuePopN(f,l,next) SllQueuePopNZ(0,f,l,next) #define SllQueuePopN(f,l,next) SllQueuePopNZ(0,f,l,next)
#define SllQueuePop(f,l) 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) \ #define DllStackPushNPZ(nil,f,n,next,prev) \
( \ ( \
@ -359,7 +360,7 @@
#define DllStackRemoveNP(f,n,next,prev) DllStackRemoveNPZ(0,f,n,next,prev) #define DllStackRemoveNP(f,n,next,prev) DllStackRemoveNPZ(0,f,n,next,prev)
#define DllStackRemove(f,n) 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) \ #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 LoadApi(ApiDesc api);
void Echo(String msg); void Echo(String msg);
b32 Panic(String msg); b32 Panic(String msg);
b32 DebugBreakPrompt(String title, String msg); b32 DebugActionPrompt(String title, String msg);
Callstack CaptureCallstack(u64 skip_frames); Callstack CaptureCallstack(u64 skip_frames);
b32 IsRunningInDebugger(void); b32 IsRunningInDebugger(void);
b32 IsRunningInWine(void); b32 IsRunningInWine(void);

View File

@ -146,7 +146,7 @@ b32 Panic(String msg)
return 0; return 0;
} }
b32 DebugBreakPrompt(String title, String msg) b32 DebugActionPrompt(String title, String msg)
{ {
LogInfoF("[DEBUG BREAK PROMPT]: %F", FmtString(msg)); LogInfoF("[DEBUG BREAK PROMPT]: %F", FmtString(msg));
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
@ -517,19 +517,54 @@ LogEventsArray GetLogEvents(void)
return result; 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 //~ Main
i32 W32_Main(void) i32 W32_Main(void)
{ {
#if IsAsanEnabled
{
__asan_set_error_report_callback(W32_AsanCallback);
}
#endif
// Init time // Init time
{ {
LARGE_INTEGER qpf; LARGE_INTEGER qpf = Zi;
QueryPerformanceFrequency(&qpf); QueryPerformanceFrequency(&qpf);
W32.ns_per_qpc = 1000000000 / qpf.QuadPart; W32.ns_per_qpc = 1000000000 / qpf.QuadPart;
} }
{ {
LARGE_INTEGER qpc; LARGE_INTEGER qpc = Zi;
QueryPerformanceCounter(&qpc); QueryPerformanceCounter(&qpc);
W32.timer_start_qpc = qpc.QuadPart; W32.timer_start_qpc = qpc.QuadPart;
} }
@ -552,20 +587,19 @@ i32 W32_Main(void)
W32.panic_event = CreateEventW(0, 1, 0, 0); W32.panic_event = CreateEventW(0, 1, 0, 0);
W32.exit_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 // Query system info
GetSystemInfo(&W32.info); GetSystemInfo(&W32.info);
// Init main thread
W32_InitCurrentThread(Lit("Main"));
W32.main_thread_id = GetCurrentThreadId();
SetThreadDescription(GetCurrentThread(), L"Main thread");
// Setup logging memory // Setup logging memory
W32.logs_arena = AcquireArena(Gibi(64)); W32.logs_arena = AcquireArena(Gibi(64));
W32.log_events_arena = AcquireArena(Gibi(64)); W32.log_events_arena = AcquireArena(Gibi(64));
W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent); W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent);
// Init main thread
W32_InitCurrentThread(Lit("Main"));
// Get raw args from command line // Get raw args from command line
Arena *perm = PermArena(); Arena *perm = PermArena();
String cmdline_str = Zi; String cmdline_str = Zi;

View File

@ -142,6 +142,11 @@ String W32_StringFromError(Arena *arena, i32 code);
void W32_LogEventToFile(LogEvent *ev, HANDLE file); void W32_LogEventToFile(LogEvent *ev, HANDLE file);
void W32_Log(i32 level, String msg); void W32_Log(i32 level, String msg);
////////////////////////////////////////////////////////////
//~ Asan
void W32_AsanCallback(char *report_cstr);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Main //~ Main

View File

@ -4008,7 +4008,7 @@ void G_D12_DebugCallback(
{ {
String description = StringFromCstrNoLimit((char *)description_cstr); String description = StringFromCstrNoLimit((char *)description_cstr);
Echo(StringF(scratch.arena, "[D3D12 DEBUG] %F\n", FmtString(description))); 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; DEBUGBREAK;
} }

View File

@ -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 (lane->idx == 0)
{ {
if (M.cmdline.target_compiler == M_CompilerKind_Msvc) if (M.cmdline.target_compiler == M_CompilerKind_Msvc)
@ -425,6 +434,11 @@ void M_BuildEntryPoint(WaveLaneCtx *lane)
M_EchoLine(Lit("[Debug build]")); 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))); 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("-DIsConsoleApp=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("-DIsAsanEnabled=0"));
}
PushStringToList(perm, &cp.defs, Lit("-DIsDebinfoEnabled=1")); PushStringToList(perm, &cp.defs, Lit("-DIsDebinfoEnabled=1"));
PushStringToList(perm, &cp.defs, Lit("-DIsDeveloperModeEnabled=1")); PushStringToList(perm, &cp.defs, Lit("-DIsDeveloperModeEnabled=1"));
PushStringToList(perm, &cp.defs, Lit("-DIsTestingEnabled=0")); 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")); 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 // TODO: Export debug info separately for release builds
PushStringToList(perm, &cp.flags_msvc, Lit("-DEBUG:FULL")); PushStringToList(perm, &cp.flags_msvc, Lit("-DEBUG:FULL"));
PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Z7")); PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Z7"));

View File

@ -141,6 +141,7 @@ Struct(M_CommandLine)
{ {
b32 release; b32 release;
b32 console; b32 console;
b32 asan;
String leaf_layer_name; String leaf_layer_name;
M_PlatformKind target_platform; M_PlatformKind target_platform;
M_CompilerKind target_compiler; M_CompilerKind target_compiler;