// stb_leakcheck.h - v0.3 - quick & dirty malloc leak-checking - public domain // LICENSE // // This software is dual-licensed to the public domain and under the following // license: you are granted a perpetual, irrevocable license to copy, modify, // publish, and distribute this file as you see fit. #ifdef STB_LEAKCHECK_IMPLEMENTATION #undef STB_LEAKCHECK_IMPLEMENTATION // don't implement more than once // if we've already included leakcheck before, undefine the macros #ifdef malloc #undef malloc #undef free #undef realloc #endif #include #include #include #include #include typedef struct malloc_info stb_leakcheck_malloc_info; struct malloc_info { char *file; int line; size_t size; stb_leakcheck_malloc_info *next,*prev; }; static stb_leakcheck_malloc_info *mi_head; void *stb_leakcheck_malloc(size_t sz, char *file, int line) { stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) malloc(sz + sizeof(*mi)); if (mi == NULL) return mi; mi->file = file; mi->line = line; mi->next = mi_head; if (mi_head) mi->next->prev = mi; mi->prev = NULL; mi->size = (int) sz; mi_head = mi; return mi+1; } void stb_leakcheck_free(void *ptr) { if (ptr != NULL) { stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1; mi->size = ~mi->size; #ifndef STB_LEAKCHECK_SHOWALL if (mi->prev == NULL) { assert(mi_head == mi); mi_head = mi->next; } else mi->prev->next = mi->next; if (mi->next) mi->next->prev = mi->prev; #endif } } void *stb_leakcheck_realloc(void *ptr, size_t sz, char *file, int line) { if (ptr == NULL) { return stb_leakcheck_malloc(sz, file, line); } else if (sz == 0) { stb_leakcheck_free(ptr); return NULL; } else { stb_leakcheck_malloc_info *mi = (stb_leakcheck_malloc_info *) ptr - 1; if (sz <= mi->size) return ptr; else { #ifdef STB_LEAKCHECK_REALLOC_PRESERVE_MALLOC_FILELINE void *q = stb_leakcheck_malloc(sz, mi->file, mi->line); #else void *q = stb_leakcheck_malloc(sz, file, line); #endif if (q) { memcpy(q, ptr, mi->size); stb_leakcheck_free(ptr); } return q; } } } void stb_leakcheck_dumpmem(void) { stb_leakcheck_malloc_info *mi = mi_head; while (mi) { if ((ptrdiff_t) mi->size >= 0) printf("LEAKED: %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) mi->size, mi+1); mi = mi->next; } #ifdef STB_LEAKCHECK_SHOWALL mi = mi_head; while (mi) { if ((ptrdiff_t) mi->size < 0) printf("FREED : %s (%4d): %8d bytes at %p\n", mi->file, mi->line, (int) ~mi->size, mi+1); mi = mi->next; } #endif } #endif // STB_LEAKCHECK_IMPLEMENTATION #ifndef INCLUDE_STB_LEAKCHECK_H #define INCLUDE_STB_LEAKCHECK_H #define malloc(sz) stb_leakcheck_malloc(sz, __FILE__, __LINE__) #define free(p) stb_leakcheck_free(p) #define realloc(p,sz) stb_leakcheck_realloc(p,sz, __FILE__, __LINE__) extern void * stb_leakcheck_malloc(size_t sz, char *file, int line); extern void * stb_leakcheck_realloc(void *ptr, size_t sz, char *file, int line); extern void stb_leakcheck_free(void *ptr); extern void stb_leakcheck_dumpmem(void); #endif // INCLUDE_STB_LEAKCHECK_H