diff options
Diffstat (limited to 'goo/gmem.cc')
-rw-r--r-- | goo/gmem.cc | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/goo/gmem.cc b/goo/gmem.cc new file mode 100644 index 0000000..7291f20 --- /dev/null +++ b/goo/gmem.cc @@ -0,0 +1,396 @@ +/* + * gmem.c + * + * Memory routines with out-of-memory checking. + * + * Copyright 1996-2003 Glyph & Cog, LLC + */ + +#include <aconf.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +// older compilers won't define SIZE_MAX in stdint.h without this +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif +#include <stdint.h> +#include <string.h> +#include <limits.h> +#if MULTITHREADED && defined(_WIN32) +# include <windows.h> +#endif +#include "gmem.h" + +#ifdef DEBUG_MEM + +typedef struct _GMemHdr { + unsigned int magic; + int index; + size_t size; + struct _GMemHdr *next, *prev; +} GMemHdr; + +#define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7) +#define gMemTrlSize (sizeof(long)) + +#define gMemMagic 0xabcd9999 + +#if ULONG_MAX > 0xffffffffL +#define gMemDeadVal 0xdeadbeefdeadbeefUL +#else +#define gMemDeadVal 0xdeadbeefUL +#endif + +/* round data size so trailer will be aligned */ +#define gMemDataSize(size) \ + (int)(((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize)) + +#define gMemDataSize64(size) \ + (size_t)(((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize)) + +static GMemHdr *gMemHead = NULL; +static GMemHdr *gMemTail = NULL; + +static int gMemIndex = 0; +static int gMemAlloc = 0; +static size_t gMemInUse = 0; +static size_t gMaxMemInUse = 0; + +#if MULTITHREADED +# ifdef _WIN32 + static CRITICAL_SECTION gMemMutex; + static INIT_ONCE gMemMutexInitStruct = INIT_ONCE_STATIC_INIT; + static BOOL CALLBACK gMemMutexInitFunc(PINIT_ONCE initOnce, PVOID param, + PVOID *context) { + InitializeCriticalSection(&gMemMutex); + return TRUE; + } +# define gMemInitMutex InitOnceExecuteOnce(&gMemMutexInitStruct, \ + &gMemMutexInitFunc, NULL, NULL) +# define gMemLock EnterCriticalSection(&gMemMutex); +# define gMemUnlock LeaveCriticalSection(&gMemMutex); +# else +# include <pthread.h> + static pthread_mutex_t gMemMutex = PTHREAD_MUTEX_INITIALIZER; +# define gMemInitMutex +# define gMemLock pthread_mutex_lock(&gMemMutex) +# define gMemUnlock pthread_mutex_unlock(&gMemMutex) +# endif +#else +# define gMemInitMutex +# define gMemLock +# define gMemUnlock +#endif + +#endif /* DEBUG_MEM */ + +#ifdef DEBUG_MEM +void *gmalloc(int size, int ignore) GMEM_EXCEP { + int size1; + char *mem; + GMemHdr *hdr; + void *data; + unsigned long *trl, *p; + + gMemInitMutex; + if (size < 0) { + gMemError("Invalid memory allocation size"); + } + if (size == 0) { + return NULL; + } + size1 = gMemDataSize(size); + if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) { + gMemError("Out of memory"); + } + hdr = (GMemHdr *)mem; + data = (void *)(mem + gMemHdrSize); + trl = (unsigned long *)(mem + gMemHdrSize + size1); + hdr->magic = gMemMagic; + hdr->size = size; + gMemLock; + if (ignore) { + hdr->index = -1; + } else { + hdr->index = gMemIndex++; + } + if (gMemTail) { + gMemTail->next = hdr; + hdr->prev = gMemTail; + gMemTail = hdr; + } else { + hdr->prev = NULL; + gMemHead = gMemTail = hdr; + } + hdr->next = NULL; + ++gMemAlloc; + gMemInUse += size; + if (gMemInUse > gMaxMemInUse) { + gMaxMemInUse = gMemInUse; + } + gMemUnlock; + for (p = (unsigned long *)data; p <= trl; ++p) { + *p = gMemDeadVal; + } + return data; +} +#else +void *gmalloc(int size) GMEM_EXCEP { + void *p; + + if (size < 0) { + gMemError("Invalid memory allocation size"); + } + if (size == 0) { + return NULL; + } + if (!(p = malloc(size))) { + gMemError("Out of memory"); + } + return p; +} +#endif + +void *grealloc(void *p, int size) GMEM_EXCEP { +#ifdef DEBUG_MEM + GMemHdr *hdr; + void *q; + int oldSize; + + if (size < 0) { + gMemError("Invalid memory allocation size"); + } + if (size == 0) { + if (p) { + gfree(p); + } + return NULL; + } + if (p) { + hdr = (GMemHdr *)((char *)p - gMemHdrSize); + oldSize = (int)hdr->size; + q = gmalloc(size); + memcpy(q, p, size < oldSize ? size : oldSize); + gfree(p); + } else { + q = gmalloc(size); + } + return q; +#else + void *q; + + if (size < 0) { + gMemError("Invalid memory allocation size"); + } + if (size == 0) { + if (p) { + free(p); + } + return NULL; + } + if (p) { + q = realloc(p, size); + } else { + q = malloc(size); + } + if (!q) { + gMemError("Out of memory"); + } + return q; +#endif +} + +void *gmallocn(int nObjs, int objSize) GMEM_EXCEP { + int n; + + if (nObjs == 0) { + return NULL; + } + n = nObjs * objSize; + if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { + gMemError("Bogus memory allocation size"); + } + return gmalloc(n); +} + +#ifdef DEBUG_MEM +void *gmalloc64(size_t size, int ignore) GMEM_EXCEP { + size_t size1; + char *mem; + GMemHdr *hdr; + void *data; + unsigned long *trl, *p; + + gMemInitMutex; + if (size == 0) { + return NULL; + } + size1 = gMemDataSize64(size); + if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) { + gMemError("Out of memory"); + } + hdr = (GMemHdr *)mem; + data = (void *)(mem + gMemHdrSize); + trl = (unsigned long *)(mem + gMemHdrSize + size1); + hdr->magic = gMemMagic; + hdr->size = size; + gMemLock; + if (ignore) { + hdr->index = -1; + } else { + hdr->index = gMemIndex++; + } + if (gMemTail) { + gMemTail->next = hdr; + hdr->prev = gMemTail; + gMemTail = hdr; + } else { + hdr->prev = NULL; + gMemHead = gMemTail = hdr; + } + hdr->next = NULL; + ++gMemAlloc; + gMemInUse += size; + if (gMemInUse > gMaxMemInUse) { + gMaxMemInUse = gMemInUse; + } + gMemUnlock; + for (p = (unsigned long *)data; p <= trl; ++p) { + *p = gMemDeadVal; + } + return data; +} +#else +void *gmalloc64(size_t size) GMEM_EXCEP { + void *p; + + if (size == 0) { + return NULL; + } + if (!(p = malloc(size))) { + gMemError("Out of memory"); + } + return p; +} +#endif + +void *gmallocn64(int nObjs, size_t objSize) GMEM_EXCEP { + size_t n; + + if (nObjs == 0) { + return NULL; + } + n = nObjs * objSize; + if (nObjs < 0 || (size_t)nObjs >= SIZE_MAX / objSize) { + gMemError("Bogus memory allocation size"); + } + return gmalloc64(n); +} + +void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP { + int n; + + if (nObjs == 0) { + if (p) { + gfree(p); + } + return NULL; + } + n = nObjs * objSize; + if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { + gMemError("Bogus memory allocation size"); + } + return grealloc(p, n); +} + +void gfree(void *p) { +#ifdef DEBUG_MEM + size_t size; + GMemHdr *hdr; + unsigned long *trl, *clr; + + if (p) { + hdr = (GMemHdr *)((char *)p - gMemHdrSize); + gMemLock; + if (hdr->magic == gMemMagic && + ((hdr->prev == NULL) == (hdr == gMemHead)) && + ((hdr->next == NULL) == (hdr == gMemTail))) { + if (hdr->prev) { + hdr->prev->next = hdr->next; + } else { + gMemHead = hdr->next; + } + if (hdr->next) { + hdr->next->prev = hdr->prev; + } else { + gMemTail = hdr->prev; + } + --gMemAlloc; + gMemInUse -= hdr->size; + gMemUnlock; + size = gMemDataSize64(hdr->size); + trl = (unsigned long *)((char *)hdr + gMemHdrSize + size); + if (*trl != gMemDeadVal) { + fprintf(stderr, "Overwrite past end of block %d at address %p\n", + hdr->index, p); + } + for (clr = (unsigned long *)hdr; clr <= trl; ++clr) { + *clr = gMemDeadVal; + } + free(hdr); + } else { + gMemUnlock; + fprintf(stderr, "Attempted to free bad address %p\n", p); + } + } +#else + if (p) { + free(p); + } +#endif +} + +void gMemError(const char *msg) GMEM_EXCEP { +#if USE_EXCEPTIONS + throw GMemException(); +#else + fprintf(stderr, "%s\n", msg); + exit(1); +#endif +} + +#ifdef DEBUG_MEM +void gMemReport(FILE *f) { + GMemHdr *p; + int left; + + fprintf(f, "%d memory allocations in all\n", gMemIndex); + fprintf(f, "maximum memory in use: %zd bytes\n", gMaxMemInUse); + left = 0; + if (gMemAlloc > 0) { + for (p = gMemHead; p; p = p->next) { + if (p->index >= 0) { + if (!left) { + fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc); + fprintf(f, " index size\n"); + fprintf(f, "-------- --------\n"); + left = 1; + } + fprintf(f, "%8d %8zd\n", p->index, p->size); + } + } + } + if (!left) { + fprintf(f, "No memory blocks left allocated\n"); + } +} +#endif + +char *copyString(const char *s) { + char *s1; + + s1 = (char *)gmalloc((int)strlen(s) + 1); + strcpy(s1, s); + return s1; +} |