From: Michael D. Lowis Date: Wed, 25 Sep 2019 00:40:15 +0000 (-0400) Subject: implemented design by contract and watchdog timer X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=5291fc12352d5487514e08ab55882bf677c661cc;p=projs%2Ftide.git implemented design by contract and watchdog timer --- diff --git a/inc/dbc.h b/inc/dbc.h index 4e5b2e0..b17d935 100644 --- a/inc/dbc.h +++ b/inc/dbc.h @@ -4,6 +4,7 @@ #define ensure(cond) \ dbc_ensure(cond, #cond, __FILE__, __LINE__) -void dbc_init(void (*)(FILE*)); +void dbc_init(char* path, void (*dumpfn)(FILE*)); void dbc_require(bool success, char* text, char* file, int line); void dbc_ensure(bool success, char* text, char* file, int line); +void dbc_wdtkick(void); diff --git a/src/lib/buf.c b/src/lib/buf.c index 4166407..f4798c1 100644 --- a/src/lib/buf.c +++ b/src/lib/buf.c @@ -22,7 +22,8 @@ static bool buf_logvalid(Log* log) { static bool buf_selvalid(Buf* buf) { (void)buf; - return true; + return (buf->selection.beg <= buf->selection.end); +// return true; } static bool buf_valid(Buf* buf) { @@ -580,10 +581,12 @@ void buf_selword(Buf* buf, bool (*isword)(Rune)) { for (; isword(buf_getrat(buf, sel.beg-1)); sel.beg--); for (; isword(buf_getrat(buf, sel.end)); sel.end++); buf->selection = sel; + ensure(buf_selvalid(buf)); } void buf_selall(Buf* buf) { buf->selection = (Sel){ .beg = 0, .end = buf_end(buf) }; + ensure(buf_selvalid(buf)); } static bool selquote(Buf* buf, Rune c) { @@ -631,6 +634,7 @@ void buf_selctx(Buf* buf, bool (*isword)(Rune)) { else buf_selword(buf, risbigword); buf_getcol(buf); + ensure(buf_selvalid(buf)); } size_t buf_byrune(Buf* buf, size_t pos, int count) { @@ -714,6 +718,7 @@ void buf_setln(Buf* buf, size_t line) { line--, curr = next; } buf->selection.beg = buf->selection.end = curr; + ensure(buf_selvalid(buf)); } void buf_getln(Buf* buf, size_t* begln, size_t* endln) { @@ -757,6 +762,7 @@ void buf_setcol(Buf* buf) { i += width; } buf->selection = sel; + ensure(buf_selvalid(buf)); } size_t buf_selbeg(Buf* buf) { @@ -792,6 +798,7 @@ void buf_selclr(Buf* buf, int dir) { buf->selection.beg = buf->selection.end; else buf->selection.end = buf->selection.beg; + ensure(buf_selvalid(buf)); } bool buf_insel(Buf* buf, size_t off) { diff --git a/src/lib/dbc.c b/src/lib/dbc.c index d35676e..ed17957 100644 --- a/src/lib/dbc.c +++ b/src/lib/dbc.c @@ -1,38 +1,58 @@ #include #include +#include +static char ErrMsg[8192]; +static char* DumpPath = NULL; static void (*DumpFn)(FILE*) = NULL; static void dump_and_abort(char* msg) { - FILE* f = fopen("/tmp/tide.dump", "w"); - fprintf(f, "%s\n", msg); + FILE* f = (DumpPath ? fopen(DumpPath, "w") : stderr); + fprintf(f, "%s\n\n", msg); if (DumpFn) DumpFn(f); fclose(f); abort(); } -void dbc_init(void (*dumpfn)(FILE*)) { -#ifndef NDEBUG +static void handle_signal(int sig) { + if (SIGBUS == sig) { + dump_and_abort("SIGBUS - Access to an undefined portion of a memory object"); + } else if (SIGFPE == sig) { + dump_and_abort("SIGFPE - Erroneous arithmetic operation"); + } else if (SIGILL == sig) { + dump_and_abort("SIGILL - Illegal instruction"); + } else if (SIGSEGV == sig) { + dump_and_abort("SIGSEGV - Invalid memory reference"); + } else if (SIGALRM == sig) { + dump_and_abort("SIGALRM - Watchdog timer expired"); + } +} + +void dbc_init(char* path, void (*dumpfn)(FILE*)) { + DumpPath = path; DumpFn = dumpfn; -#endif + signal(SIGBUS, handle_signal); + signal(SIGFPE, handle_signal); + signal(SIGILL, handle_signal); + signal(SIGSEGV, handle_signal); } void dbc_require(bool success, char* text, char* file, int line) { -#ifndef NDEBUG - char buf[8192]; if (!success) { - snprintf(buf, sizeof(buf), "%s:%d: pre-condition failed (%s)", file, line, text); - dump_and_abort(buf); + snprintf(ErrMsg, sizeof(ErrMsg), "%s:%d: pre-condition failed (%s)", file, line, text); + dump_and_abort(ErrMsg); } -#endif } void dbc_ensure(bool success, char* text, char* file, int line) { -#ifndef NDEBUG - char buf[8192]; if (!success) { - snprintf(buf, sizeof(buf), "%s:%d: post-condition failed (%s)", file, line, text); - dump_and_abort(buf); + snprintf(ErrMsg, sizeof(ErrMsg), "%s:%d: post-condition failed (%s)", file, line, text); + dump_and_abort(ErrMsg); } -#endif +} + +void dbc_wdtkick(void) { + alarm(0); /* Cancel previous alarm */ + signal(SIGALRM, handle_signal); + alarm(1); /* Start new alarm */ } diff --git a/src/tide.c b/src/tide.c index 75adb2b..c21d88d 100644 --- a/src/tide.c +++ b/src/tide.c @@ -47,6 +47,41 @@ static char* SearchTerm = NULL; #define PRESSED(mods, btn) \ ((mods & (1 << (btn + 7))) == (1 << (btn + 7))) +/* Crash Dump Handling + ******************************************************************************/ +void dumpdata(FILE* f) { + fprintf(f, "Focused:\t%d\n", Focused); + fprintf(f, "Divider:\t%d\n", Divider); + fprintf(f, "FontSel:\t%d\n", FontSel); + fprintf(f, "SyncMouse:\t%d\n", SyncMouse); + fprintf(f, "SearchDir:\t%d\n", SearchDir); + fprintf(f, "SearchTerm:\t'%s'\n", SearchTerm); + for (int i = 0; i < NREGIONS; i++) { + fprintf(f, "Region[%d]:\n", i); + fprintf(f, "\t.sync_flags:\t%d\n", Regions[i].sync_flags); + fprintf(f, "\t.index:\t\t%zu\n", Regions[i].index); + fprintf(f, "\t.width:\t\t%zu\n", Regions[i].width); + fprintf(f, "\t.nvisible:\t%zu\n", Regions[i].nvisible); + fprintf(f, "\t.nrows:\t\t%zu\n", Regions[i].nrows); + fprintf(f, "\t.rows:\t\t%p\n", (void*)Regions[i].rows); + fprintf(f, "\t.buffer:\n"); + fprintf(f, "\t\t.status:\t%d\n", Regions[i].buffer.status); + fprintf(f, "\t\t.modtime:\t%llu\n", Regions[i].buffer.modtime); + fprintf(f, "\t\t.bufsize:\t%zu\n", Regions[i].buffer.bufsize); + fprintf(f, "\t\t.bufstart:\t%p\n", (void*)Regions[i].buffer.bufstart); + fprintf(f, "\t\t.bufend:\t%p\n", (void*)Regions[i].buffer.bufend); + fprintf(f, "\t\t.gapstart:\t%p\n", (void*)Regions[i].buffer.gapstart); + fprintf(f, "\t\t.gapend:\t%p\n", (void*)Regions[i].buffer.gapend); + fprintf(f, "\t\t.undo:\t\t%p\n", (void*)Regions[i].buffer.undo); + fprintf(f, "\t\t.redo:\t\t%p\n", (void*)Regions[i].buffer.redo); + fprintf(f, "\t\t.save:\t\t%p\n", (void*)Regions[i].buffer.save); + fprintf(f, "\t\t.transid:\t%d\n", Regions[i].buffer.transid); + fprintf(f, "\t\t.selbeg:\t%zu\n", Regions[i].buffer.selection.beg); + fprintf(f, "\t\t.selend:\t%zu\n", Regions[i].buffer.selection.end); + fprintf(f, "\t\t.selcol:\t%zu\n", Regions[i].buffer.selection.col); + } +} + /* X11 Window Code ******************************************************************************/ static void font_load(char* name) { @@ -287,6 +322,7 @@ void win_loop(void) { int maxcount = 1000 / Timeout; int count = 0; while (X.running) { + dbc_wdtkick(); bool ready = job_poll(Timeout); count += (ready ? -count : 1); if (count < maxcount) @@ -672,6 +708,7 @@ int main(int argc, char** argv) { view_resize(win_view(TAGS), 640, 1); buf_logclear(win_buf(TAGS)); win_prop_set("TIDE", "", "tide"); + dbc_init(NULL, dumpdata); /* if we still have args left we're going to open it in this instance */ if (*argv) {