http://ozlabs.org/~jk/code/
<tb@panthema.net>
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <locale.h>
#include <dlfcn.h>
#include "malloc_count.h"
static const int log_operations = 0;
static const size_t log_operations_threshold = 1024*1024;
#define THREAD_SAFE_GCC_INTRINSICS 0
typedef void* (*malloc_type)(size_t);
typedef void (*free_type)(void*);
typedef void* (*realloc_type)(void*, size_t);
static malloc_type real_malloc = NULL;
static free_type real_free = NULL;
static realloc_type real_realloc = NULL;
static const size_t sentinel = 0xDEADC0DE;
#define INIT_HEAP_SIZE 1024*1024
static char init_heap[INIT_HEAP_SIZE];
static size_t init_heap_use = 0;
static const int log_operations_init_heap = 0;
static long long peak = 0, curr = 0, total = 0;
static malloc_count_callback_type callback = NULL;
static void* callback_cookie = NULL;
static void inc_count(size_t inc)
{
#if THREAD_SAFE_GCC_INTRINSICS
long long mycurr = __sync_add_and_fetch(&curr, inc);
if (mycurr > peak) peak = mycurr;
total += inc;
if (callback) callback(callback_cookie, mycurr);
#else
if ((curr += inc) > peak) peak = curr;
total += inc;
if (callback) callback(callback_cookie, curr);
#endif
}
static void dec_count(size_t dec)
{
#if THREAD_SAFE_GCC_INTRINSICS
long long mycurr = __sync_sub_and_fetch(&curr, dec);
if (callback) callback(callback_cookie, mycurr);
#else
curr -= dec;
if (callback) callback(callback_cookie, curr);
#endif
}
extern size_t malloc_count_current(void)
{
return curr;
}
extern size_t malloc_count_peak(void)
{
return peak;
}
extern void malloc_count_reset_peak(void)
{
peak = curr;
}
extern void malloc_count_print_status(void)
{
fprintf(stderr,"malloc_count ### current %'lld, peak %'lld\n",
curr, peak);
}
void malloc_count_set_callback(malloc_count_callback_type cb, void* cookie)
{
callback = cb;
callback_cookie = cookie;
}
extern void* malloc(size_t size)
{
void* ret;
if (size == 0) return NULL;
if (real_malloc)
{
ret = (*real_malloc)(2*sizeof(size_t) + size);
inc_count(size);
if (log_operations && size >= log_operations_threshold) {
fprintf(stderr,"malloc_count ### malloc(%'lld) = %p (current %'lld)\n",
(long long)size, (char*)ret + 2*sizeof(size_t), curr);
}
((size_t*)ret)[0] = size;
((size_t*)ret)[1] = sentinel;
return (char*)ret + 2*sizeof(size_t);
}
else
{
if (init_heap_use + sizeof(size_t) + size > INIT_HEAP_SIZE) {
fprintf(stderr,"malloc_count ### init heap full !!!\n");
exit(EXIT_FAILURE);
}
ret = init_heap + init_heap_use;
init_heap_use += 2*sizeof(size_t) + size;
((size_t*)ret)[0] = size;
((size_t*)ret)[1] = sentinel;
if (log_operations_init_heap) {
fprintf(stderr,"malloc_count ### malloc(%'lld) = %p on init heap\n",
(long long)size, (char*)ret + 2*sizeof(size_t));
}
return (char*)ret + 2*sizeof(size_t);
}
}
extern void free(void* ptr)
{
size_t size;
if (!ptr) return;
if ((char*)ptr >= init_heap &&
(char*)ptr <= init_heap + init_heap_use)
{
if (log_operations_init_heap) {
fprintf(stderr,"malloc_count ### free(%p) on init heap\n", ptr);
}
return;
}
if (!real_free) {
fprintf(stderr,"malloc_count ### free(%p) outside init heap and without real_free !!!\n", ptr);
return;
}
ptr = (char*)ptr - 2*sizeof(size_t);
if (((size_t*)ptr)[1] != sentinel) {
fprintf(stderr,"malloc_count ### free(%p) has no sentinel !!! memory corruption?\n", ptr);
}
size = ((size_t*)ptr)[0];
dec_count(size);
if (log_operations && size >= log_operations_threshold) {
fprintf(stderr,"malloc_count ### free(%p) -> %'lld (current %'lld)\n",
ptr, (long long)size, curr);
}
(*real_free)(ptr);
}
extern void* calloc(size_t nmemb, size_t size)
{
void* ret;
size *= nmemb;
if (!size) return NULL;
ret = malloc(size);
memset(ret, 0, size);
return ret;
}
extern void* realloc(void* ptr, size_t size)
{
void* newptr;
size_t oldsize;
if ((char*)ptr >= (char*)init_heap &&
(char*)ptr <= (char*)init_heap + init_heap_use)
{
if (log_operations_init_heap) {
fprintf(stderr,"malloc_count ### realloc(%p) = on init heap\n", ptr);
}
ptr = (char*)ptr - 2*sizeof(size_t);
if (((size_t*)ptr)[1] != sentinel) {
fprintf(stderr,"malloc_count ### realloc(%p) has no sentinel !!! memory corruption?\n", ptr);
}
oldsize = ((size_t*)ptr)[0];
if (oldsize >= size) {
((size_t*)ptr)[0] = size;
return (char*)ptr + 2*sizeof(size_t);
}
else {
ptr = (char*)ptr + 2*sizeof(size_t);
newptr = malloc(size);
memcpy(newptr, ptr, oldsize);
free(ptr);
return newptr;
}
}
if (size == 0) {
free(ptr);
return NULL;
}
if (ptr == NULL) {
return malloc(size);
}
ptr = (char*)ptr - 2*sizeof(size_t);
if (((size_t*)ptr)[1] != sentinel) {
fprintf(stderr,"malloc_count ### free(%p) has no sentinel !!! memory corruption?\n", ptr);
}
oldsize = ((size_t*)ptr)[0];
dec_count(oldsize);
inc_count(size);
newptr = (*real_realloc)(ptr, 2*sizeof(size_t) + size);
if (log_operations && size >= log_operations_threshold)
{
if (newptr == ptr)
fprintf(stderr,"malloc_count ### realloc(%'lld -> %'lld) = %p (current %'lld)\n",
(long long)oldsize, (long long)size, newptr, curr);
else
fprintf(stderr,"malloc_count ### realloc(%'lld -> %'lld) = %p -> %p (current %'lld)\n",
(long long)oldsize, (long long)size, ptr, newptr, curr);
}
((size_t*)newptr)[0] = size;
return (char*)newptr + 2*sizeof(size_t);
}
static __attribute__((constructor)) void init(void)
{
char *error;
setlocale(LC_NUMERIC, "");
dlerror();
real_malloc = (malloc_type)dlsym(RTLD_NEXT, "malloc");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "malloc_count ### error %s\n", error);
exit(EXIT_FAILURE);
}
real_realloc = (realloc_type)dlsym(RTLD_NEXT, "realloc");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "malloc_count ### error %s\n", error);
exit(EXIT_FAILURE);
}
real_free = (free_type)dlsym(RTLD_NEXT, "free");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "malloc_count ### error %s\n", error);
exit(EXIT_FAILURE);
}
}
static __attribute__((destructor)) void finish(void)
{
fprintf(stderr,"malloc_count ### exiting, total: %'lld, peak: %'lld, current: %'lld\n",
total, peak, curr);
}