cepheid

An Aurora 4X clone
Log | Files | Refs | README

commit c84e89a8004432b711ad8d780998d718966f73d4
parent b5b3c6139f452b95dee5ff6a271322e7b5925a05
Author: hhvn <dev@hhvn.uk>
Date:   Wed, 23 Nov 2022 20:15:27 +0000

Error-checking allocation

Diffstat:
MMakefile | 5+----
Adev/checkalloc.sh | 8++++++++
Msrc/bdb.c | 6+++---
Msrc/body.c | 2+-
Msrc/db.c | 2+-
Asrc/err.c | 35+++++++++++++++++++++++++++++++++++
Msrc/loading.c | 2+-
Msrc/main.c | 30------------------------------
Msrc/main.h | 25++++++++++++++++++++++---
Asrc/mem.c | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/save.c | 2+-
Msrc/str.c | 53+++++++++++++++++------------------------------------
Msrc/system.c | 10+++++-----
Msrc/tree.c | 6+++---
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;