From c024b3b241b212c4cca11a0b8c8969ef8986a1b1 Mon Sep 17 00:00:00 2001 From: bumbread Date: Sun, 19 Jun 2022 16:24:36 +1100 Subject: [PATCH] Assert stack trace --- bake.cmd | 2 +- inc/_os.h | 3 ++ src/code/assert.c | 3 ++ src/code/stdio/fmt_print.h | 70 ++++++++++++++++++++------------------ src/code/string.c | 2 +- src/win/win_except.c | 28 +++++++++++++++ test/test_assert.c | 11 +++++- 7 files changed, 83 insertions(+), 36 deletions(-) diff --git a/bake.cmd b/bake.cmd index 28ffbc2..88c572e 100644 --- a/bake.cmd +++ b/bake.cmd @@ -44,5 +44,5 @@ llvm-ar rc ciabatta.lib bin\*.obj bin\%PLATFORM%\*.obj if "%TEST%"=="" set TEST=assert echo Compiling test_%TEST%.c -clang -fno-builtin test\test_%TEST%.c ciabatta.lib -std=c11 -lkernel32 -luser32 -lshell32 -nostdlib %CIABATTA_OPTIONS% +clang -fno-builtin test\test_%TEST%.c ciabatta.lib -std=c11 -lDbghelp -lkernel32 -luser32 -lshell32 -nostdlib %CIABATTA_OPTIONS% ::cl test\test_math.c /Iinc -D_CRT_SECURE_NO_WARNINGS /Z7 /link ciabatta.lib kernel32.lib user32.lib shell32.lib -nostdlib -nodefaultlibs diff --git a/inc/_os.h b/inc/_os.h index 58cd699..96c8468 100644 --- a/inc/_os.h +++ b/inc/_os.h @@ -27,6 +27,9 @@ typedef struct _OS_ModeFlags { } _OS_ModeFlags; typedef struct FILE FILE; + +void _os_print_stack_trace(); + int _os_del_file(char const *filename); int _os_mov_file(char const *old, char const *new); char *_os_tmpname(char *buffer); diff --git a/src/code/assert.c b/src/code/assert.c index d3a5f3e..4446259 100644 --- a/src/code/assert.c +++ b/src/code/assert.c @@ -3,6 +3,7 @@ #include // printf #include // abort +#include <_os.h> // stack trace void _Noreturn _assert( char const *cond, @@ -14,5 +15,7 @@ void _Noreturn _assert( printf(" Function: %s\n", func); printf(" File: %s\n", file); printf(" Line: %d\n", line); + printf("Trace:\n"); + _os_print_stack_trace(); abort(); } diff --git a/src/code/stdio/fmt_print.h b/src/code/stdio/fmt_print.h index 5efd24f..3f993b9 100644 --- a/src/code/stdio/fmt_print.h +++ b/src/code/stdio/fmt_print.h @@ -58,7 +58,11 @@ ArgConv arg_conv; }; - inline static uint64_t get_int_arg(Format *fmt, va_list args, bool *signp) { + inline static uint64_t get_int_arg( + Format *fmt, + va_list *args, + bool *signp + ) { bool sign = 0; uint64_t num = 0; @@ -66,7 +70,7 @@ // If we've got HH or H we need to parse as int, and do the necessary conv // to unsigned if needed. if(fmt->arg_len < LEN_I) { - int ch = va_arg(args, int); + int ch = va_arg(*args, int); if(ch < 0) { if(fmt->flag_unsigned) { num = ch + (fmt->arg_len == LEN_HH? UCHAR_MAX : USHRT_MAX); @@ -82,12 +86,12 @@ // plus handle the sign else if(fmt->flag_unsigned) { switch(fmt->arg_len) { - case LEN_I: num = va_arg(args, unsigned int); break; - case LEN_L: num = va_arg(args, unsigned long); break; - case LEN_LL: num = va_arg(args, unsigned long long); break; - case LEN_J: num = va_arg(args, uintmax_t); break; - case LEN_Z: num = va_arg(args, size_t); break; - case LEN_T: num = va_arg(args, size_t); break; + case LEN_I: num = va_arg(*args, unsigned int); break; + case LEN_L: num = va_arg(*args, unsigned long); break; + case LEN_LL: num = va_arg(*args, unsigned long long); break; + case LEN_J: num = va_arg(*args, uintmax_t); break; + case LEN_Z: num = va_arg(*args, size_t); break; + case LEN_T: num = va_arg(*args, size_t); break; default:; } } @@ -95,12 +99,12 @@ // TODO: signed size_t int64_t i = 0; switch(fmt->arg_len) { - case LEN_I: i = va_arg(args, int); break; - case LEN_L: i = va_arg(args, long); break; - case LEN_LL: i = va_arg(args, long long); break; - case LEN_J: i = va_arg(args, uintmax_t); break; - case LEN_Z: i = va_arg(args, int64_t); break; - case LEN_T: i = va_arg(args, ptrdiff_t); break; + case LEN_I: i = va_arg(*args, int); break; + case LEN_L: i = va_arg(*args, long); break; + case LEN_LL: i = va_arg(*args, long long); break; + case LEN_J: i = va_arg(*args, uintmax_t); break; + case LEN_Z: i = va_arg(*args, int64_t); break; + case LEN_T: i = va_arg(*args, ptrdiff_t); break; default:; } if(i < 0) { @@ -143,7 +147,7 @@ inline static int suffix(fmt_atoi)(fchar const *str, int *value) { inline static int suffix(fmt_parse)( Format *format, fchar const *str, - va_list args + va_list *args ) { *format = (Format){0}; // Parse flags @@ -161,7 +165,7 @@ inline static int suffix(fmt_parse)( int width = 0; if(str[i] == '*') { ++i; - width = va_arg(args, int); + width = va_arg(*args, int); if(width < 0) { width = -width; format->flag_zero = true; @@ -178,7 +182,7 @@ inline static int suffix(fmt_parse)( ++i; if(str[i] == '*') { ++i; - prec = va_arg(args, int); + prec = va_arg(*args, int); if(prec < 0) { prec = 0; } @@ -333,7 +337,7 @@ inline static int suffix(fmt_fprint_int)( void *ctx, suffix(out_func_t) *out, Format *fmt, - va_list args + va_list *args ) { int w = 0; @@ -448,10 +452,10 @@ inline static int suffix(fmt_fprint_ptr)( void *ctx, suffix(out_func_t) *out, Format *fmt, - va_list args + va_list *args ) { int w = 0; - uintptr_t num = va_arg(args, uintptr_t); + uintptr_t num = va_arg(*args, uintptr_t); int s_len = 2 + 16; // length of significant chars int d_len = s_len; // length of all displayed chars @@ -530,7 +534,7 @@ inline static int suffix(fmt_fprint_char)( void *ctx, suffix(out_func_t) *out, Format *fmt, - va_list args + va_list *args ) { int w = 0; bool sign; @@ -570,10 +574,10 @@ inline static int suffix(fmt_just_fucking_print_float_someone_improve_this_later void *ctx, suffix(out_func_t) *out, Format *fmt, - va_list args + va_list *args ) { int w = 0; - double f = va_arg(args, double); + double f = va_arg(*args, double); uint64_t i = (uint64_t)f; char digits_arr[33] = {0}; @@ -616,10 +620,10 @@ inline static int suffix(fmt_fprint_str)( void *ctx, suffix(out_func_t) *out, Format *fmt, - va_list args + va_list *args ) { int w = 0; - char *str = va_arg(args, char *); + char *str = va_arg(*args, char *); uint64_t len = strlen(str); // Calculate padding @@ -666,31 +670,31 @@ inline static int suffix(fmt_print)( if(fmt[i] == '%') { ++i; Format format; - int fmt_len = suffix(fmt_parse)(&format, fmt+i, args); + int fmt_len = suffix(fmt_parse)(&format, fmt+i, &args); if(fmt_len < 0) return -1; i += fmt_len; int written; switch(format.arg_conv) { case CONV_INT: { - written = suffix(fmt_fprint_int)(ctx, out, &format, args); + written = suffix(fmt_fprint_int)(ctx, out, &format, &args); } break; case CONV_FLT: { - written = suffix(fmt_just_fucking_print_float_someone_improve_this_later)(ctx, out, &format, args); + written = suffix(fmt_just_fucking_print_float_someone_improve_this_later)(ctx, out, &format, &args); } break; case CONV_EXP: { - written = suffix(fmt_just_fucking_print_float_someone_improve_this_later)(ctx, out, &format, args); + written = suffix(fmt_just_fucking_print_float_someone_improve_this_later)(ctx, out, &format, &args); } break; case CONV_SCI: { - written = suffix(fmt_just_fucking_print_float_someone_improve_this_later)(ctx, out, &format, args); + written = suffix(fmt_just_fucking_print_float_someone_improve_this_later)(ctx, out, &format, &args); } break; case CONV_CHAR: { - written = suffix(fmt_fprint_char)(ctx, out, &format, args); + written = suffix(fmt_fprint_char)(ctx, out, &format, &args); } break; case CONV_STR: { - written = suffix(fmt_fprint_str)(ctx, out, &format, args); + written = suffix(fmt_fprint_str)(ctx, out, &format, &args); } break; case CONV_PTR: { - written = suffix(fmt_fprint_ptr)(ctx, out, &format, args); + written = suffix(fmt_fprint_ptr)(ctx, out, &format, &args); } break; case CONV_N: { int *n = va_arg(args, int *); diff --git a/src/code/string.c b/src/code/string.c index b6bedaa..d3197a0 100644 --- a/src/code/string.c +++ b/src/code/string.c @@ -88,7 +88,7 @@ int strcmp(const char *s1, const char *s2) { int diff; do { diff = *s1 - *s2; - } while(diff != 0 && *s1 != 0 && *s2 != 0); + } while(diff == 0 && *s1++ != 0 && *s2++ != 0); return diff; } diff --git a/src/win/win_except.c b/src/win/win_except.c index 0df42d2..b10c88a 100644 --- a/src/win/win_except.c +++ b/src/win/win_except.c @@ -3,9 +3,14 @@ #define WIN32_LEAN_AND_MEAN #include +#include #include #include +#include +#include +#include +#include #define _countof(arr) (sizeof (arr) / sizeof ((arr)[0])) @@ -49,6 +54,29 @@ static LONG _win32_handler(EXCEPTION_POINTERS *ExceptionInfo) { return EXCEPTION_CONTINUE_SEARCH; } +void _os_print_stack_trace() { + HANDLE process = GetCurrentProcess(); + SymInitialize(process, NULL, TRUE); + + void *stack[128]; + USHORT frames = CaptureStackBackTrace(2, 128, stack, NULL); + + SYMBOL_INFO* symbol = calloc(sizeof(SYMBOL_INFO)+256, 1); + symbol->MaxNameLen = 255; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + for(size_t i = 0; i < frames; i++) { + SymFromAddr(process, (DWORD64)stack[i], 0, symbol); + if(strcmp(symbol->Name, "BaseThreadInitThunk") == 0) break; + if(strcmp(symbol->Name, "mainCRTStartup") == 0) break; + printf(" %u: 0x%"PRIx64" (%s)\n", + (int)(frames-i-1), + symbol->Address, + symbol->Name + ); + } + free(symbol); +} + void _os_init_eh() { void *res = AddVectoredExceptionHandler(1, &_win32_handler); if(res == NULL) { diff --git a/test/test_assert.c b/test/test_assert.c index 5304081..bca2603 100644 --- a/test/test_assert.c +++ b/test/test_assert.c @@ -1,7 +1,16 @@ #include +#include + +void do_more_stuff(char *ptr) { + assert(ptr != NULL); +} + +void do_stuff() { + do_more_stuff(NULL); +} int main() { assert(2+2 == 4); - assert(0 != 0); // Bad case of assert + do_stuff(); }