]> git.mdlowis.com Git - projs/tide.git/commitdiff
implemented design by contract and watchdog timer
authorMichael D. Lowis <mike@mdlowis.com>
Wed, 25 Sep 2019 00:40:15 +0000 (20:40 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Wed, 25 Sep 2019 00:40:15 +0000 (20:40 -0400)
inc/dbc.h
src/lib/buf.c
src/lib/dbc.c
src/tide.c

index 4e5b2e01b2b98d49c895bcdcb4fad9f912685eb0..b17d935270ba90c3b56ad4a6909f085621714a66 100644 (file)
--- 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);
index 4166407da1aff26b09d81372ace5bb0f6c6bc045..f4798c12a7cf5ffba1f60250a03fadd50f1c0ec3 100644 (file)
@@ -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) {
index d35676eb4486c7af5f16a3a6ab703b84c4de5115..ed179570bbaa50f8a11fb6f0991030e10f45bb75 100644 (file)
@@ -1,38 +1,58 @@
 #include <dbc.h>
 #include <stdio.h>
+#include <signal.h>
 
+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 */
 }
index 75adb2bad596c8e1d2cbf283673e3dde37988e37..c21d88da2e0899793ba6bfd9de9af15d3c58df81 100644 (file)
@@ -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) {