commit c84e89a8004432b711ad8d780998d718966f73d4
parent b5b3c6139f452b95dee5ff6a271322e7b5925a05
Author: hhvn <dev@hhvn.uk>
Date: Wed, 23 Nov 2022 20:15:27 +0000
Error-checking allocation
Diffstat:
14 files changed, 180 insertions(+), 88 deletions(-)
diff --git a/Makefile b/Makefile
@@ -41,11 +41,8 @@ data-clean:
@echo $(DATADIR): make clean
@cd $(DATADIR); make clean
-tags: $(SRC)
- ctags --exclude=data/*.h --exclude=data/icons/*.h -R .
-
# ignore generated headers
sloccount:
sloccount $(SRC) $(DBDIR)
-.PHONY: all db db-clean dbtool data data-clean
+.PHONY: all clean db db-clean dbtool data data-clean
diff --git a/dev/checkalloc.sh b/dev/checkalloc.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# GNU grep only
+command -v ggrep >/dev/null && grep="ggrep" || grep="grep"
+
+# Final grep is required for the return value to indicate
+# existance of any calls to non error-checking allocators
+! $grep -nE '[^fen](malloc|calloc|realloc|strdup)\(' src/*.c | $grep -v mem.c | $grep .
diff --git a/src/bdb.c b/src/bdb.c
@@ -159,21 +159,21 @@ _bdbget(char *dir, char *group, ...) {
break;
case 'S':
v.S = va_arg(ap, char ***);
- *v.S = malloc(len * sizeof(char *));
+ *v.S = emalloc(len * sizeof(char *));
for (i = 0; i < len; i++)
(*v.S)[i] = nstrdup(list[i]);
*va_arg(ap, int *) = len;
break;
case 'I':
v.I = va_arg(ap, int **);
- *v.I = malloc(len * sizeof(int));
+ *v.I = emalloc(len * sizeof(int));
for (i = 0; i < len; i++)
(*v.I)[i] = atoi(list[i]);
*va_arg(ap, int *) = len;
break;
case 'F':
v.F = va_arg(ap, float **);
- *v.F = malloc(len * sizeof(float));
+ *v.F = emalloc(len * sizeof(float));
for (i = 0; i < len; i++)
(*v.F)[i] = strtol(list[i], NULL, 10);
*va_arg(ap, int *) = len;
diff --git a/src/body.c b/src/body.c
@@ -44,7 +44,7 @@ Body *
body_init(char *name) {
Body *ret;
- ret = malloc(sizeof(Body));
+ ret = emalloc(sizeof(Body));
if (!ret) return NULL;
ret->name = nstrdup(name);
ret->t = NULL;
diff --git a/src/db.c b/src/db.c
@@ -128,7 +128,7 @@ dbgettree(char *dir, Tree *r, Treegetter func) {
for (i = 0, ppath = path = NULL, t = r; i < glen; i++) {
free(ppath);
ppath = path;
- path = strdup(groups[i]);
+ path = estrdup(groups[i]);
memcpy(&psplit, split, sizeof(split));
pslen = slen;
diff --git a/src/err.c b/src/err.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "main.h"
+
+/* see main.h for macros */
+
+#define BOLD "\033[1m"
+#define FG "\033[38;5;%dm"
+#define STANDOUT BOLD FG
+#define NORMAL "\033[0m"
+
+void
+_err(int code, char *type, char *file, int line, const char *func, char *fmt, ...) {
+ va_list ap;
+ int col = (code >= 0 ? 160 : 166);
+
+ fprintf(stderr, STANDOUT ">>>" NORMAL " At %s:%d in %s\n"
+ STANDOUT ">>>" NORMAL " %s: ", col, file, line, func, col, type);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+#ifdef DEBUG
+ raise(SIGTRAP);
+#else
+ if (code >= 1024)
+ raise(code - RAISE);
+ if (code >= 0)
+ exit(code);
+#endif /* DEBUG */
+}
+
+
diff --git a/src/loading.c b/src/loading.c
@@ -39,7 +39,7 @@ loading_open(int steps, char *initstr) {
char curstr[LOAD_STR_MAX];
struct sigaction sa;
- ret = malloc(sizeof(Loader));
+ ret = emalloc(sizeof(Loader));
if (!ret) return NULL;
snprintf(ret->path, sizeof(ret->path), "/%ld-loading", (long)getpid());
diff --git a/src/main.c b/src/main.c
@@ -13,36 +13,6 @@ int sigterm = 0;
int quit = 0;
int view_before_smenu = VIEW_MAIN;
-void
-error(int code, char *fmt, ...) {
- va_list ap;
-
- fprintf(stderr, "error: ");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
-#ifdef DEBUG
- raise(SIGTRAP);
-#else
- exit(code);
-#endif /* DEBUG */
-}
-
-void
-warning(char *fmt, ...) {
- va_list ap;
-
- fprintf(stderr, "warning: ");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
-#ifdef DEBUG
- raise(SIGTRAP);
-#endif /* DEBUG */
-}
-
static void
sighandler(int signal) {
switch (signal) {
diff --git a/src/main.h b/src/main.h
@@ -16,19 +16,38 @@
return func(*(type*)a, *(type*)b); \
}
+#ifdef CHECK_FRAME_MEM_FREE
+#define CUSTOM_FREE
+#endif /* CHECK_FRAME_MEM_FREE */
+
+#ifdef CUSTOM_FREE
+#define free(m) _free(m, __FILE__, __LINE__, __func__)
+#endif /* CUSTOM_FREE */
+
/* main.c */
extern Save *save;
extern int sigint;
extern int sigterm;
extern int quit;
extern int view_before_smenu;
-void error(int code, char *fmt, ...);
-void warning(char *fmt, ...);
-/* str.c */
+/* err.c */
+#define ERR(code, type, fmt, ...) _err(code, type, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__)
+#define error(code, fmt, ...) ERR(code, "error", fmt, ##__VA_ARGS__)
+#define warning(fmt, ...) ERR(-1, "warning", fmt, ##__VA_ARGS__)
+void _err(int code, char *type, char *file, int line, const char *func, char *fmt, ...);
+
+/* mem.c */
void * falloc(size_t size);
void ffree(void);
char * fstrdup(char *str);
+void * emalloc(size_t size);
+void * estrdup(char *str);
+void * ecalloc(size_t nmemb, size_t size);
+void * erealloc(void *pt, size_t size);
+void _free(void *mem, char *file, int line, const char *func);
+
+/* str.c */
char * vsfprintf(char *fmt, va_list args);
char * sfprintf(char *fmt, ...); /* return string allocated for current frame */
char * vsmprintf(char *fmt, va_list args);
diff --git a/src/mem.c b/src/mem.c
@@ -0,0 +1,82 @@
+#include <stdlib.h>
+#include <string.h>
+#include "main.h"
+
+#define NOMEM() error(2, "out of memory\n")
+#define MCHECK(x) (x != NULL ? (void)0 : NOMEM())
+#define FMEMMAX 1024
+
+static void *fmem[FMEMMAX] = {NULL};
+static int fmemi = 0;
+
+/* allocate for a frame */
+void *
+falloc(size_t size) {
+ if (fmemi + 1 == FMEMMAX)
+ NOMEM();
+ return (fmem[fmemi++] = emalloc(size));
+}
+
+void
+ffree(void) {
+ while (fmemi--) {
+ free(fmem[fmemi]);
+ fmem[fmemi] = NULL;
+ }
+ fmemi = 0;
+}
+
+char *
+fstrdup(char *str) {
+ char *ret;
+
+ if (!str) return NULL;
+
+ ret = falloc(strlen(str) + 1);
+ strcpy(ret, str);
+ return ret;
+}
+
+void *
+emalloc(size_t size) {
+ void *ret = malloc(size);
+ MCHECK(ret);
+ return ret;
+}
+
+void *
+estrdup(char *str) {
+ void *ret = strdup(str);
+ MCHECK(ret);
+ return ret;
+}
+
+void *
+ecalloc(size_t nmemb, size_t size) {
+ void *ret = calloc(nmemb, size);
+ MCHECK(ret);
+ return ret;
+}
+
+void *
+erealloc(void *ptr, size_t size) {
+ void *ret = realloc(ptr, size);
+ MCHECK(ret);
+ return ret;
+}
+
+#ifdef CUSTOM_FREE
+#undef free
+#endif /* CUSTOM_FREE */
+
+void
+_free(void *mem, char *file, int line, const char *func) {
+#ifdef CHECK_FRAME_MEM_FREE
+ int i;
+ for (i = fmemi; i >= 0; i--)
+ if (fmem[i] == mem)
+ _err(2, "error", file, line, func,
+ "attempting to free memory allocated for a frame\n");
+#endif /* CHECK_FRAME_MEM_FREE */
+ free(mem);
+}
diff --git a/src/save.c b/src/save.c
@@ -25,7 +25,7 @@ save_read(char *name) {
if (save)
save_free();
- if (!name || !(save = malloc(sizeof(Save))))
+ if (!name || !(save = emalloc(sizeof(Save))))
return;
snprintf(dir, sizeof(dir), "%s/%s", SAVEDIR, name);
diff --git a/src/str.c b/src/str.c
@@ -10,46 +10,27 @@
#include "main.h"
#define TEXTBUF 2048
-#define FMEMMAX 1024
-
-static void *fmem[FMEMMAX] = {NULL};
-static int fmemi = 0;
-
-/* allocate for a frame */
-void *
-falloc(size_t size) {
- if (fmemi + 1 == FMEMMAX) {
- errno = ENOMEM;
- return NULL;
- }
- return (fmem[fmemi++] = malloc(size));
-}
-
-void
-ffree(void) {
- while (fmemi--) {
- free(fmem[fmemi]);
- fmem[fmemi] = NULL;
- }
- fmemi = 0;
-}
char *
-fstrdup(char *str) {
+vsfprintf(char *fmt, va_list args) {
+ va_list ap;
+ int size;
char *ret;
- ret = falloc(strlen(str) + 1);
- strcpy(ret, str);
- return ret;
-}
+ va_copy(ap, args);
+ size = vsnprintf(NULL, 0, fmt, ap) + 1;
+ va_end(ap);
-char *
-vsfprintf(char *fmt, va_list ap) {
- if (fmemi + 1 == FMEMMAX) {
- errno = ENOMEM;
+ if (size == 0) /* -1 */
return NULL;
- }
- return (fmem[fmemi++] = vsmprintf(fmt, ap));
+
+ ret = falloc(size);
+ if (!ret) return NULL;
+
+ va_copy(ap, args);
+ vsnprintf(ret, size, fmt, ap);
+ va_end(ap);
+ return ret;
}
char *
@@ -76,7 +57,7 @@ vsmprintf(char *fmt, va_list args) {
if (size == 0) /* -1 */
return NULL;
- ret = malloc(size);
+ ret = emalloc(size);
if (!ret) return NULL;
va_copy(ap, args);
@@ -102,7 +83,7 @@ nstrdup(char *str) {
errno = EINVAL;
return NULL;
}
- return strdup(str);
+ return estrdup(str);
}
char *
diff --git a/src/system.c b/src/system.c
@@ -37,7 +37,7 @@ sys_get_polar(Body *body) {
System *
sys_init(char *name) {
- System *ret = malloc(sizeof(System));
+ System *ret = emalloc(sizeof(System));
if (!ret) return NULL;
ret->name = nstrdup(name);
ret->t = NULL;
@@ -90,8 +90,8 @@ sys_tree_load(void) {
/* bn & bp are only free'd at the end to avoid excess (re)allocations */
bl = 10;
- bn = malloc(bl * sizeof(char *));
- bp = malloc(bl * sizeof(char *));
+ bn = emalloc(bl * sizeof(char *));
+ bp = emalloc(bl * sizeof(char *));
for (t = save->systems.d; t; t = t->n) {
s = t->data;
@@ -100,8 +100,8 @@ sys_tree_load(void) {
for (i = 0, bt = t->d; bt; bt = bt->n, i++) {
if (i == bl - 1) {
bl += 10;
- bn = realloc(bn, bl * sizeof(char *));
- bp = realloc(bp, bl * sizeof(char *));
+ bn = erealloc(bn, bl * sizeof(char *));
+ bp = erealloc(bp, bl * sizeof(char *));
}
bn[i] = bt->name;
diff --git a/src/tree.c b/src/tree.c
@@ -23,7 +23,7 @@ tree_add_child(Tree *t, char *name, int type, void *data, Tree **ptr) {
if (!t) return NULL;
- e = malloc(sizeof(Tree));
+ e = emalloc(sizeof(Tree));
if (!e) return NULL;
e->p = e->n = e->d = NULL;
@@ -236,12 +236,12 @@ tree_sort(Tree *t, Treecompar compar, void *cdata) {
/* The tree can't be sorted (i,e, modified) whilst iterating through it. */
sl = 10;
- s = malloc(sl * sizeof(Tree *));
+ s = emalloc(sl * sizeof(Tree *));
for (p = NULL, si = 0; tree_iter_f(t, TREEMAX, &p, &depth, tree_sort_filter, NULL) != -1; si++) {
if (si == sl - 1) {
sl += 10;
- s = realloc(s, sl * sizeof(Tree *));
+ s = erealloc(s, sl * sizeof(Tree *));
}
s[si] = p;