>From 73c47a162ddc455f265d7eb29eaad5474f9a678e Mon Sep 17 00:00:00 2001 From: Brand Huntsman Date: Sun, 14 Jan 2018 23:19:37 -0700 Subject: [PATCH] restore terminal and print backtrace for segfaults and assertions Signed-off-by: Brand Huntsman --- src/Makefile.am | 3 +++ src/nano.c | 27 ++++++++++++++++++++++++--- src/nano.h | 9 ++++++++- src/proto.h | 1 + 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 625434c2..f9422e47 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,9 @@ AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" -DSYSCONFDIR=\"$(sysconfdir)\" \ -I$(top_builddir)/lib -I$(top_srcdir)/lib +# -rdynamic is needed by print_backtrace() to show function names +LDFLAGS = -rdynamic + CLEANFILES = revision.h if BUILDING_FROM_GIT diff --git a/src/nano.c b/src/nano.c index a21625cf..63abee1b 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1890,8 +1890,32 @@ void do_output(char *output, size_t output_len, bool allow_cntrls) update_line(openfile->current, openfile->current_x); } +void print_backtrace(int skip_to) +{ + void *callstack[16]; + int i, frames = backtrace(callstack, 16); + char **strings = backtrace_symbols(callstack, frames); + for(i = skip_to + 1; i < frames; i++) printf("| %s\n", strings[i]); + free(strings); + exit(1); +} + +void segfault_handler(int nothing) +{ + endwin(); + tcsetattr(0, TCSANOW, &oldterm); + printf("Segmentation fault\n"); + print_backtrace(1); /* hide segfault_handler() */ +} + int main(int argc, char **argv) { + /* Initialize segfault handler. */ + signal(SIGSEGV, segfault_handler); + + /* Back up the terminal settings so that they can be restored. */ + tcgetattr(0, &oldterm); + int stdin_flags, optchr; #if defined(ENABLED_WRAPORJUSTIFY) && defined(ENABLE_NANORC) bool fill_used = FALSE; @@ -1985,9 +2009,6 @@ int main(int argc, char **argv) console = (getenv("DISPLAY") == NULL); #endif - /* Back up the terminal settings so that they can be restored. */ - tcgetattr(0, &oldterm); - /* Get the state of standard input and ensure it uses blocking mode. */ stdin_flags = fcntl(0, F_GETFL, 0); if (stdin_flags != -1) diff --git a/src/nano.h b/src/nano.h index 55abf1e8..f2239dfb 100644 --- a/src/nano.h +++ b/src/nano.h @@ -120,7 +120,14 @@ #include #include #include -#include +#include + +#define assert(expr) if(!(expr)){ \ + endwin(); \ + tcsetattr(0, TCSANOW, &oldterm); \ + printf("Assertion (%s) failed: %s %s() %d\n", #expr, __FILE__, __func__, __LINE__); \ + print_backtrace(0); \ +} /* If we aren't using an ncurses with mouse support, exclude any * mouse routines, as they are useless then. */ diff --git a/src/proto.h b/src/proto.h index d82d0cbd..a52d4ab1 100644 --- a/src/proto.h +++ b/src/proto.h @@ -446,6 +446,7 @@ int do_input(bool allow_funcs); int do_mouse(void); #endif void do_output(char *output, size_t output_len, bool allow_cntrls); +void print_backtrace(int skip_to); /* Most functions in prompt.c. */ #ifdef ENABLE_MOUSE -- 2.13.6