--- /dev/null
+#ifdef CHECK_ALLOC
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "chkalloc.h"
+#include "util.h"
+
+#define OFFSET 512
+
+struct allocation {
+ char *ptr;
+ char *file;
+ int fullsz, sz;
+ int lineno;
+ struct allocation *next;
+};
+
+static FILE *logfile;
+static struct allocation *alist, *atail;
+
+static void init_once(void)
+{
+ static int init_once_done;
+ if(!init_once_done) {
+ init_once_done = 1;
+ remove("chk.log");
+ }
+}
+
+static FILE *openlog(void)
+{
+ if(logfile) return logfile;
+ return (logfile = fopen("chk.log", "a"));
+}
+
+static void closelog(void)
+{
+ fclose(logfile);
+ logfile = 0;
+}
+
+static void mark_alloc(struct allocation *a)
+{
+ uintptr_t *left, *right, *end;
+
+ left = (uintptr_t*)(a + 1);
+ right = (uintptr_t*)((char*)a + a->fullsz) - 1;
+ end = (uintptr_t*)(a->ptr + a->sz);
+
+ while(left + 1 < (void*)a->ptr) {
+ *left = (uintptr_t)left;
+ left++;
+ }
+ while(right >= end) {
+ *right = (uintptr_t)right;
+ right--;
+ }
+}
+
+static int check_alloc(struct allocation *a, const char *reason)
+{
+ int i;
+ uintptr_t *left = (uintptr_t*)(a + 1);
+ uintptr_t *right = (uintptr_t*)((char*)a + a->fullsz) - 1;
+ void *end = a->ptr + a->sz;
+ int trash_left = 0, trash_right = 0;
+ char *last_trash_left = 0, *first_trash_right = 0;
+ char *first_trash_left = 0, *last_trash_right = 0;
+
+ init_once();
+ if(!openlog()) return -1;
+
+ while(left + 1 < (void*)a->ptr) {
+ if(*left != (uintptr_t)left) {
+ fprintf(logfile, "@%p: %p\n", left, (void*)*left);
+ }
+ for(i=0; i<sizeof *left; i++) {
+ int s = i << 3;
+ if(((*left >> s) & 0xff) != (((uintptr_t)left >> s) & 0xff)) {
+ if(!first_trash_left) first_trash_left = (char*)left;
+ trash_left++;
+ last_trash_left = (char*)left + i;
+ }
+ }
+ left++;
+ }
+ while(right >= end) {
+ if(*right != (uintptr_t)right) {
+ fprintf(logfile, "@%p: %p\n", right, (void*)*right);
+ }
+ for(i=0; i<sizeof *right; i++) {
+ int s = i << 3;
+ if(((*right >> s) & 0xff) != (((uintptr_t)right >> s) & 0xff)) {
+ if(!last_trash_right) last_trash_right = (char*)right;
+ trash_right++;
+ first_trash_right = (char*)right + i;
+ }
+ }
+ right--;
+ }
+
+ if(!(trash_left | trash_right)) return 0;
+
+ fprintf(logfile, "corrupted memory allocated from: %s:%d\n", a->file, a->lineno);
+ if(trash_left) {
+ fprintf(logfile, " %d bytes at offset %d before start (%p)\n",
+ (int)(last_trash_left - first_trash_left),
+ (int)(a->ptr - last_trash_left), a->ptr);
+ }
+ if(trash_right) {
+ fprintf(logfile, " %d bytes at offset %d after end (%p)\n",
+ (int)(last_trash_right - first_trash_right),
+ (int)(first_trash_right - end), end);
+ }
+ fprintf(logfile, " check due to %s\n", reason);
+ closelog();
+ return -1;
+}
+
+void chk_check(void)
+{
+ struct allocation *anode = alist;
+ while(anode) {
+ check_alloc(anode, "explicit check call");
+ anode = anode->next;
+ }
+}
+
+void *chk_malloc_impl(int sz, char *file, int line)
+{
+ int fullsz;
+ struct allocation *a;
+
+ init_once();
+
+ fullsz = sz + OFFSET * 2;
+ if(!(a = malloc(fullsz))) {
+ return 0;
+ }
+
+ a->ptr = (char*)a + OFFSET;
+ a->file = file;
+ a->lineno = line;
+ a->fullsz = fullsz;
+ a->sz = sz;
+ a->next = 0;
+
+ if(alist) {
+ atail->next = a;
+ atail = a;
+ } else {
+ alist = atail = a;
+ }
+
+ mark_alloc(a);
+
+ if(openlog()) {
+ fprintf(logfile, "alloc(%d) from %s:%d\n", sz, a->file, a->lineno);
+ closelog();
+ }
+ return a->ptr;
+}
+
+void *chk_realloc_impl(void *ptr, int sz, char *file, int line)
+{
+ int fullsz;
+ struct allocation *newptr;
+ struct allocation *a = (struct allocation*)((char*)ptr - OFFSET);
+ struct allocation *prev, dummy;
+
+ init_once();
+ if(ptr) {
+ check_alloc(a, "realloc");
+ }
+
+ fullsz = sz + OFFSET * 2;
+ if(!(newptr = realloc(a, fullsz))) {
+ return 0;
+ }
+
+ dummy.next = alist;
+ prev = &dummy;
+ while(prev->next) {
+ if(prev->next == a) {
+ prev->next = newptr;
+ break;
+ }
+ prev = prev->next;
+ }
+ alist = dummy.next;
+
+ a = newptr;
+ a->ptr = (char*)a + OFFSET;
+ a->sz = sz;
+ a->fullsz = fullsz;
+ a->file = file;
+ a->lineno = line;
+
+ mark_alloc(a);
+
+ if(openlog()) {
+ fprintf(logfile, "realloc(%d) from %s:%d\n", sz, a->file, a->lineno);
+ closelog();
+ }
+ return a->ptr;
+}
+
+void chk_free(void *p)
+{
+ struct allocation dummy, *prev, *a;
+
+ init_once();
+
+ if(!p) return;
+
+ a = (struct allocation*)((char*)p - OFFSET);
+ if(openlog()) {
+ fprintf(logfile, "free() %d allocated from %s:%d\n", a->sz, a->file, a->lineno);
+ closelog();
+ }
+
+ dummy.next = alist;
+ prev = &dummy;
+ while(prev->next) {
+ if(prev->next->ptr == p) {
+ a = prev->next;
+ prev->next = a->next;
+
+ check_alloc(a, "free");
+ free(a);
+ break;
+ }
+ prev = prev->next;
+ }
+ alist = dummy.next;
+}
+
+#endif /* CHECK_ALLOC */