You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
124 lines
3.3 KiB
124 lines
3.3 KiB
// stb_leakcheck.h - v0.2 - 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 <assert.h> |
|
#include <string.h> |
|
#include <stdlib.h> |
|
#include <stdio.h> |
|
#include <stddef.h> |
|
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
|
|
|