Awful Allocation Tracking Macro in C

So a few years ago while I was still actively writing code in D, I’d watched a talk by the illustrious Andrei Alexandrescu. … and he’d mentioned you could probably write a macro in C that would statically track allocations throughout your program if you routed your allocations through it.

Of course, I immediately took to the streets and figured this deserved an attempt.

What I produced then, preserved in one of my gists is the following:

#include <stdlib.h>
#include <stdio.h>

struct Node {

    size_t attempted_allocations;
    size_t successful_allocations;
    size_t size;

    struct Node* next;

    const char* file;
    size_t line;

};

static struct Node *head = NULL;

#define COMBINE(x, y) x ## y
#define EVAL(x, y) COMBINE(x, y)

#define NAME node
#define ALLOC(MEM, SZ) \
    static struct Node EVAL(NAME, __LINE__); \
    if (!EVAL(NAME, __LINE__).next) { \
        EVAL(NAME, __LINE__).line = __LINE__; \
        EVAL(NAME, __LINE__).file = __FILE__; \
    } \
    if (head && !EVAL(NAME, __LINE__).next) { \
        struct Node* last = head; \
        head = &EVAL(NAME, __LINE__); \
        head->next = last; \
    } \
    if (!head) head = &EVAL(NAME, __LINE__); \
    MEM = malloc(SZ); \
    EVAL(NAME, __LINE__).attempted_allocations += 1; \
    if (MEM) { \
        EVAL(NAME, __LINE__).successful_allocations += 1; \
        EVAL(NAME, __LINE__).size += SZ; \
    } \

void do_thing() {
    void *other_mem;
    ALLOC(other_mem, 1024)
}

int main(int argc, char **argv) {

    void *mem;
    ALLOC(mem, 2048)
    ALLOC(mem, 1024000000000000000)

    do_thing();
    do_thing();

    struct Node *cur;
    printf("allocations: \n");
    for (cur = head; cur != NULL; cur = cur->next) {
        printf(
            "allocation - attempted num: %zu, successful num: %zu, size: %zu, line: %zu, file: %s\n",
            cur->attempted_allocations,
            cur->successful_allocations,
            cur->size, cur->line,
            cur->file
        );
    }

    return 0;

}

Look ma, no heap allocations (to track the allocations at least)!

Improvements?

It would be nice if this could be a single expression, I know with GCC’s Statement Expressions you could probably accomplish this and our calls could instead look like this (both nicer and less error prone):

void* mem = ALLOC(2048); // all the memory

… instead of what we’re currently stuck with.

If someone has any suggestions for other ways to attack this though, feel free to email me and I’d love to include it in the article, because we all need more effective ways to write the worst code of our lives.

… if anything it might let us identify someone doing it in a live setting :) (but mostly I just enjoy it)