OP commented "a large number of buffers are dynamically allocated, ... ". The malloc()
, realloc()
, calloc()
, free()
, etc could be re-written with a wrapper function that stores the size.
typedef union {
max_align_t align;
size_t sz;
} my_header;
void* my_malloc(size_t size) {
my_header *p = malloc(sizeof *p + size);
if (p) {
p->sz = size;
p++;
}
return p;
}
size_t my_size(const void *p) {
if (p) {
const my_header *head = p;
return head[-1].sz;
}
return 0;
}
void my_free(void *p) {
if (p) {
my_header *head = p;
free(--head);
}
}
All other *.c files call some *.h file with
#define malloc my_malloc
#define free my_free
void *my_malloc(size_t size);
void my_free(void *p);
size_t my_size(const void *p);
Now when my_sprintf()
is called with an allocated pointer ...
int my_sprintf (char *dest,char *format,...) {
va_list va;
va_start(va,format);
size_t n = my_size(dest);
return vsnprintf(dest,n,format,va);
}
Further, a magic number could also be pre-pended to help identify if the pointer passed is truly a my_allcoated()
one.
Wrapping allocation functions is also a way to determine various allocation concerns: double free, max usage, all pointers free'd, ...
[Edit] after 5 years.
Code needs to ensure alignment - code re-worked.
With pre-C11 use a union of wide types in lieu of max_align_t
.
typedef union {
double d;
long l;
void *p;
void (*fp)();
// With C99
complex long double cld;
long long ll;
size_t sz;
} my_header;