Here's a little project I hacked up that shows how you can track memory allocations by using a macro to replace malloc() & free() with your own function, and using a linked list to store the allocations.
A note on portability (to avoid some pedant pointing it out later):
It does use some trickery to find the original pointer - it is not 100% portable, but all compilers I've ever used [which is a reasonable selection of the most popular ones and a few less common ones] allow using negative indices to pointers to "walk backwards" in memory. It could be done more portable by casting pointers to char * and adding/subtracting the sizeof(struct memblk).
trackmalloc.h:
Code:
#ifndef TRACK_MALLOC_H
#define TRACK_MALLOC_H
#ifndef INTERNAL
#define malloc(size) trackmalloc(size, #size, __FILE__, __LINE__)
#define free(ptr) trackfree(ptr, #ptr, __FILE__, __LINE__)
#endif
void *trackmalloc(size_t size, const char *expr, const char *file, int line);
void trackfree(void *ptr, const char *expr, const char *file, int line);
void trackListAllocations();
#endif
trackmalloc.c:
Code:
#define INTERNAL
#include "trackmalloc.h"
#include <stdlib.h>
#include <stdio.h>
struct memblk
{
long magic;
struct memblk *next;
struct memblk *prev;
size_t size;
const char *file;
const char *expr;
int line;
int padding; // Make it an even 16 byte length (total size=32 bytes in 32-bit mode).
};
#define MAGIC1 0x12345678
#define MAGIC2 0x87654321
struct memblk *memblockList = NULL;
static void trackMBDetails(struct memblk *mb)
{
printf("%d bytes allocated with \"%s\" at %s:%d\n", mb->size, mb->expr, mb->file, mb->line);
}
void *trackmalloc(size_t size, const char *expr, const char *file, int line)
{
struct memblk *mb = malloc(size + sizeof(*mb));
if (!mb)
{
// May want to output some error message here!
return NULL;
}
mb->magic = MAGIC1;
mb->file = file;
mb->line = line;
mb->expr = expr;
mb->size = size;
mb->prev = NULL;
mb->next = memblockList;
if (memblockList)
{
memblockList->prev = mb;
}
memblockList = mb;
return (void *)&mb[1];
}
void trackfree(void *ptr, const char *expr, const char *file, int line)
{
if (!ptr)
return;
else
{
struct memblk *mb = &((struct memblk *)(ptr))[-1];
if (mb->magic != MAGIC1)
{
if (mb->magic == MAGIC2)
{
printf("Attempt to free already freed memory:\n");
trackMBDetails(mb);
}
else
{
printf("Invalid free of ptr %p (expr=\"%s\" from %s:%d\n", (void *)ptr, expr, file, line);
}
return;
}
mb->magic = MAGIC2;
if (mb == memblockList)
{
memblockList = mb->next;
}
// Unlink it.
if (mb->next)
mb->next->prev = mb->prev;
if (mb->prev)
mb->prev->next = mb->next;
free(mb);
}
}
void trackListAllocations(void)
{
printf("*** Allocation list start ***\n");
if (!memblockList)
{
printf(">>> EMPTY <<<\n");
}
else
{
struct memblk *mb;
for(mb = memblockList; mb; mb = mb->next)
{
trackMBDetails(mb);
}
}
printf("*** Allocation list end ***\n");
}
Sample of usage:
main.c:
Code:
#include "trackmalloc.h"
#include <stdio.h>
int main()
{
int *ptr = malloc(sizeof(int) * 4);
int *arrPtr[100];
int i;
ptr[0] = '0';
ptr[1] = '1';
ptr[2] = '2';
ptr[3] = '3';
printf("%d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]);
for(i = 0; i < 100; i++)
{
arrPtr[i] = malloc(10 * sizeof(int));
}
free(ptr);
for(i = 0; i < 50; i++)
{
free(arrPtr[i]);
}
trackListAllocations();
for(; i < 100; i++)
{
free(arrPtr[i]);
}
return 0;
}
--
Mats