Print stack trace on assert() failure or when calling fatal_error()

Note: this uses the __sanitizer_print_stack_trace() function from the
AddressSanitizer runtime, so it only works when AddressSanitizer is
in use.
This commit is contained in:
Craig Barnes 2021-01-15 20:39:45 +00:00
parent bcf46d9eab
commit 22f25a9e4f
23 changed files with 125 additions and 37 deletions

View file

@ -4,12 +4,12 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#define LOG_MODULE "base64" #define LOG_MODULE "base64"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "debug.h"
enum { enum {
P = 1 << 6, // Padding byte (=) P = 1 << 6, // Padding byte (=)

View file

@ -4,7 +4,6 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <getopt.h> #include <getopt.h>
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
@ -16,6 +15,7 @@
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "client-protocol.h" #include "client-protocol.h"
#include "debug.h"
#include "foot-features.h" #include "foot-features.h"
#include "version.h" #include "version.h"
#include "xmalloc.h" #include "xmalloc.h"

View file

@ -6,7 +6,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <ctype.h> #include <ctype.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <pwd.h> #include <pwd.h>
#include <fcntl.h> #include <fcntl.h>
@ -21,6 +20,7 @@
#define LOG_MODULE "config" #define LOG_MODULE "config"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "debug.h"
#include "input.h" #include "input.h"
#include "macros.h" #include "macros.h"
#include "tokenize.h" #include "tokenize.h"

2
csi.c
View file

@ -3,7 +3,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#if defined(_DEBUG) #if defined(_DEBUG)
@ -16,6 +15,7 @@
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "config.h" #include "config.h"
#include "debug.h"
#include "grid.h" #include "grid.h"
#include "selection.h" #include "selection.h"
#include "sixel.h" #include "sixel.h"

48
debug.c Normal file
View file

@ -0,0 +1,48 @@
#include "debug.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#if defined(__SANITIZE_ADDRESS__) || HAS_FEATURE(address_sanitizer)
#include <sanitizer/asan_interface.h>
#define ASAN_ENABLED 1
#endif
static void
print_stack_trace(void)
{
#ifdef ASAN_ENABLED
fputs("\nStack trace:\n", stderr);
__sanitizer_print_stack_trace();
#endif
}
noreturn void
fatal_error(const char *msg, int err)
{
syslog(LOG_ERR, "%s: %s", msg, strerror(err));
errno = err;
perror(msg);
print_stack_trace();
abort();
}
noreturn void
bug(const char *file, int line, const char *func, const char *fmt, ...)
{
fprintf(stderr, "\n%s:%d: BUG in %s(): ", file, line, func);
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
print_stack_trace();
fflush(stderr);
abort();
}

32
debug.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include "macros.h"
#ifdef NDEBUG
#define BUG(...) UNREACHABLE()
#else
#define BUG(...) bug(__FILE__, __LINE__, __func__, __VA_ARGS__)
#endif
#undef assert
#define assert(x) do { \
IGNORE_WARNING("-Wtautological-compare") \
if (unlikely(!(x))) { \
BUG("assertion failed: '%s'", #x); \
} \
UNIGNORE_WARNINGS \
} while (0)
#ifndef static_assert
#if __STDC_VERSION__ >= 201112L
#define static_assert(x, msg) _Static_assert((x), msg)
#elif GNUC_AT_LEAST(4, 6) || HAS_EXTENSION(c_static_assert)
#define static_assert(x, msg) __extension__ _Static_assert((x), msg)
#else
#define static_assert(x, msg)
#endif
#endif
noreturn void fatal_error(const char *msg, int err) COLD;
noreturn void bug(const char *file, int line, const char *func, const char *fmt, ...) PRINTF(4) COLD;

2
fdm.c
View file

@ -5,7 +5,6 @@
#include <inttypes.h> #include <inttypes.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/epoll.h> #include <sys/epoll.h>
@ -15,6 +14,7 @@
#define LOG_MODULE "fdm" #define LOG_MODULE "fdm"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "debug.h"
struct handler { struct handler {
int fd; int fd;

2
grid.c
View file

@ -1,11 +1,11 @@
#include "grid.h" #include "grid.h"
#include <string.h> #include <string.h>
#include <assert.h>
#define LOG_MODULE "grid" #define LOG_MODULE "grid"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "debug.h"
#include "macros.h" #include "macros.h"
#include "sixel.h" #include "sixel.h"
#include "util.h" #include "util.h"

14
log.c
View file

@ -1,15 +1,15 @@
#include "log.h" #include "log.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h> #include <unistd.h>
#include <syslog.h> #include "debug.h"
static bool colorize = false; static bool colorize = false;
static bool do_syslog = true; static bool do_syslog = true;

View file

@ -27,6 +27,21 @@
#define HAS_BUILTIN(x) 0 #define HAS_BUILTIN(x) 0
#endif #endif
#ifdef __has_feature
#define HAS_FEATURE(x) __has_feature(x)
#else
#define HAS_FEATURE(x) 0
#endif
// __has_extension() is a Clang macro used to determine if a feature is
// available even if not standardized in the current "-std" mode.
#ifdef __has_extension
#define HAS_EXTENSION(x) __has_extension(x)
#else
// Clang versions prior to 3.0 only supported __has_feature()
#define HAS_EXTENSION(x) HAS_FEATURE(x)
#endif
#if GNUC_AT_LEAST(3, 0) || HAS_ATTRIBUTE(unused) || defined(__TINYC__) #if GNUC_AT_LEAST(3, 0) || HAS_ATTRIBUTE(unused) || defined(__TINYC__)
#define UNUSED __attribute__((__unused__)) #define UNUSED __attribute__((__unused__))
#else #else
@ -139,11 +154,11 @@
#define XSTRDUP XMALLOC NONNULL_ARGS #define XSTRDUP XMALLOC NONNULL_ARGS
#if __STDC_VERSION__ >= 201112L #if __STDC_VERSION__ >= 201112L
#define NORETURN _Noreturn #define noreturn _Noreturn
#elif GNUC_AT_LEAST(3, 0) #elif GNUC_AT_LEAST(3, 0)
#define NORETURN __attribute__((__noreturn__)) #define noreturn __attribute__((__noreturn__))
#else #else
#define NORETURN #define noreturn
#endif #endif
#if CLANG_AT_LEAST(3, 6) #if CLANG_AT_LEAST(3, 6)

View file

@ -106,6 +106,7 @@ version = custom_target(
misc = static_library( misc = static_library(
'misc', 'misc',
'debug.c', 'debug.h',
'hsl.c', 'hsl.h', 'hsl.c', 'hsl.h',
'log.c', 'log.h', 'log.c', 'log.h',
'macros.h', 'macros.h',
@ -180,6 +181,7 @@ executable(
executable( executable(
'footclient', 'footclient',
'client.c', 'client-protocol.h', 'client.c', 'client-protocol.h',
'debug.c', 'debug.h',
'foot-features.h', 'foot-features.h',
'log.c', 'log.h', 'log.c', 'log.h',
'macros.h', 'macros.h',

View file

@ -5,11 +5,12 @@
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/signalfd.h> #include <sys/signalfd.h>
#include <tllist.h>
#define LOG_MODULE "reaper" #define LOG_MODULE "reaper"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "tllist.h" #include "debug.h"
struct child { struct child {
pid_t pid; pid_t pid;

View file

@ -593,7 +593,6 @@ execute_binding(struct seat *seat, struct terminal *term,
case BIND_ACTION_SEARCH_EDIT_LEFT_WORD: { case BIND_ACTION_SEARCH_EDIT_LEFT_WORD: {
size_t diff = distance_prev_word(term); size_t diff = distance_prev_word(term);
term->search.cursor -= diff; term->search.cursor -= diff;
assert(term->search.cursor >= 0);
assert(term->search.cursor <= term->search.len); assert(term->search.cursor <= term->search.len);
return false; return false;
} }
@ -606,7 +605,6 @@ execute_binding(struct seat *seat, struct terminal *term,
case BIND_ACTION_SEARCH_EDIT_RIGHT_WORD: { case BIND_ACTION_SEARCH_EDIT_RIGHT_WORD: {
size_t diff = distance_next_word(term); size_t diff = distance_next_word(term);
term->search.cursor += diff; term->search.cursor += diff;
assert(term->search.cursor >= 0);
assert(term->search.cursor <= term->search.len); assert(term->search.cursor <= term->search.len);
return false; return false;
} }

2
shm.c
View file

@ -2,7 +2,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h> #include <limits.h>
@ -22,6 +21,7 @@
#define LOG_MODULE "shm" #define LOG_MODULE "shm"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "debug.h"
#include "macros.h" #include "macros.h"
#include "xmalloc.h" #include "xmalloc.h"

View file

@ -6,6 +6,7 @@
#define LOG_MODULE "sixel" #define LOG_MODULE "sixel"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "debug.h"
#include "render.h" #include "render.h"
#include "hsl.h" #include "hsl.h"
#include "util.h" #include "util.h"

View file

@ -6,7 +6,6 @@
#include <ctype.h> #include <ctype.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <signal.h> #include <signal.h>
#include <termios.h> #include <termios.h>
@ -18,6 +17,7 @@
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "debug.h"
#include "terminal.h" #include "terminal.h"
#include "tokenize.h" #include "tokenize.h"
#include "xmalloc.h" #include "xmalloc.h"

View file

@ -2,7 +2,6 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -11,6 +10,7 @@
#define LOG_MODULE "spawn" #define LOG_MODULE "spawn"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "debug.h"
bool bool
spawn(struct reaper *reaper, const char *cwd, char *const argv[], spawn(struct reaper *reaper, const char *cwd, char *const argv[],

View file

@ -3,7 +3,6 @@
#include <malloc.h> #include <malloc.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -22,6 +21,7 @@
#include "async.h" #include "async.h"
#include "config.h" #include "config.h"
#include "debug.h"
#include "extract.h" #include "extract.h"
#include "grid.h" #include "grid.h"
#include "ime.h" #include "ime.h"

View file

@ -12,6 +12,7 @@
#include <fcft/fcft.h> #include <fcft/fcft.h>
//#include "config.h" //#include "config.h"
#include "debug.h"
#include "fdm.h" #include "fdm.h"
#include "macros.h" #include "macros.h"
#include "reaper.h" #include "reaper.h"

2
uri.c
View file

@ -4,11 +4,11 @@
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#define LOG_MODULE "uri" #define LOG_MODULE "uri"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "debug.h"
#include "xmalloc.h" #include "xmalloc.h"
enum { enum {

2
vt.c
View file

@ -3,13 +3,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#define LOG_MODULE "vt" #define LOG_MODULE "vt"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "csi.h" #include "csi.h"
#include "dcs.h" #include "dcs.h"
#include "debug.h"
#include "grid.h" #include "grid.h"
#include "osc.h" #include "osc.h"
#include "util.h" #include "util.h"

View file

@ -1,21 +1,11 @@
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <wchar.h> #include <wchar.h>
#include <syslog.h>
#include "xmalloc.h" #include "xmalloc.h"
#include "debug.h"
static NORETURN COLD void
fatal_error(const char *msg, int err)
{
syslog(LOG_ERR, "%s: %s", msg, strerror(err));
errno = err;
perror(msg);
abort();
}
static void * static void *
check_alloc(void *alloc) check_alloc(void *alloc)

View file

@ -1,8 +1,8 @@
#include "xsnprintf.h" #include "xsnprintf.h"
#include <assert.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include "debug.h"
size_t size_t
xvsnprintf(char *buf, size_t n, const char *format, va_list ap) xvsnprintf(char *buf, size_t n, const char *format, va_list ap)