tcmart14 For one's own code, it's not so hard to write a simple GC. Here's something I hacked up quickly:
Makefile
CC= gcc
CFLAGS= -Wall -Wextra -pedantic -O -g -fno-omit-frame-pointer
LDFLAGS=
SRC= pmgc_test.c pmgc.c
pmgc_test: ${SRC} pmgc.h
${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${SRC}
clean:
rm -f *.o pmgc_test
pmgc_test.c
#include <stdio.h>
#include <stdlib.h>
#include "pmgc.h"
int
main(void)
{
char *p, *p1, *p2, *p3;
size_t i;
atexit(FFree);
p1 = Malloc(100);
p2 = Malloc(4096);
p2 = Realloc(p2, 16 * 1024);
p3 = Calloc(1, 8192);
Free(p3);
#ifdef DO_TEST
p3 = Realloc(p3, 512); /* invalid realloc */
Free(p3); /* double free */
#endif
for (i = 0; i < 4096; i++) {
p = Malloc(4096);
if (arc4random() & 1)
Free(p);
}
return 0;
}
pmgc.h
/**
* Poor Man's Garbage Collector.
*/
#define Malloc(x) xMalloc( (x), __FILE__, __LINE__)
#define Calloc(x, y) xCalloc( (x), (y), __FILE__, __LINE__)
#define Realloc(x, y) xRealloc( (x), (y), __FILE__, __LINE__)
#define Free(x) xFree( (x), __FILE__, __LINE__)
/* Public Decls. */
void* xMalloc(size_t size, char* fn, int lno);
void* xRealloc(void* ptr, size_t size, char* fn, int lno);
void* xCalloc(size_t num, size_t size, char* fn, int lno);
void xFree(void* ptr, char* fn, int lno);
void FFree(void);
pmgc.c
/**
* Poor Man's Garbage Collector:
* Record allocated pointers in an array (grown as needed),
* then free all pointers at exit.
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
/* Private decls. */
enum { NOTFOUND = -1 };
static ssize_t getslot(void* ptr);
static void grow(char* fn, int lno);
static void addptr(void* ptr, void* old, char* fn, int lno);
/* Private vars. */
static void** P = NULL; /* Pointer array--can have gaps */
static size_t N = 0; /* Grow array if N == MAX */
static size_t MAX = 0; /* Array size */
/**
* Public functions
*/
void*
xMalloc(size_t size, char* fn, int lno)
{
void* p = malloc(size);
if (p == NULL)
return NULL;
addptr(p, NULL, fn, lno);
return p;
}
void*
xCalloc(size_t num, size_t size, char* fn, int lno)
{
void* p = calloc(num, size);
if (p == NULL)
return NULL;
addptr(p, NULL, fn, lno);
return p;
}
void*
xRealloc(void* ptr, size_t size, char* fn, int lno)
{
if (ptr != NULL) { /* do a sanity check first */
ssize_t i = getslot(ptr);
if (i == NOTFOUND)
errx(1, "%s:%d: invalid ptr: %p", fn, lno, ptr);
}
void* p = realloc(ptr, size);
if (p == NULL)
return NULL;
addptr(p, ptr, fn, lno);
return p;
}
void
xFree(void* ptr, char* fn, int lno)
{
if (ptr == NULL)
return;
ssize_t i = getslot(ptr);
if (i == NOTFOUND)
errx(1, "%s:%d: invalid ptr: %p", fn, lno, ptr);
free(P[i]);
P[i] = NULL; /* slot is free */
}
/**
* Final Free
*/
void
FFree(void)
{
size_t i;
for (i = 0; i < N; i++)
free(P[i]);
free(P);
P = NULL;
N = MAX = 0;
}
/**
* Private funcs.
*/
static ssize_t
getslot(void* ptr)
{
size_t i;
for (i = 0; i < N; i++) {
if (P[i] == ptr)
return i;
}
return NOTFOUND;
}
static void
grow(char* fn, int lno)
{
size_t newsz;
void* p;
if (N < MAX)
return;
newsz = (MAX > 0 ? MAX * 2 : 256);
p = realloc(P, newsz * sizeof (void *));
if (p == NULL)
err(1, "grow():%s:%d: out of memory", fn, lno);
P = p;
MAX = newsz;
}
static void
addptr(void* ptr, void* old, char* fn, int lno)
{
ssize_t i;
if (ptr == NULL) /* somebody goofed */
errx(1, "%s:%d: NULL ptr", fn, lno);
if (old == NULL) { /* malloc, calloc */
grow(fn, lno); /* may have to add entry */
i = getslot(ptr);
if (i != NOTFOUND) /* XXX: raging paranoia */
errx(1, "%s:%d: duplicate ptr: %p", fn, lno, ptr);
i = getslot(NULL); /* find empty slot */
if (i == NOTFOUND)
P[N++] = ptr; /* add new entry */
else
P[i] = ptr; /* record new entry */
} else { /* realloc */
i = getslot(old); /* find existing slot */
if (i == NOTFOUND)
errx(1, "%s:%d: invalid ptr: %p", fn, lno, ptr);
P[i] = ptr; /* replace entry */
}
}