So many different mallocs - do we need them?

I have a really odd problem that I described here. I try to get my head around this issue and came across this in memory.h:

#define NEW(t)           (t*)zmalloc(sizeof(t))
#define N_NEW(n,t)       (t*)gcalloc((n),sizeof(t))
#define GNEW(t)          (t*)gmalloc(sizeof(t))

#define N_GNEW(n,t)      (t*)gcalloc((n),sizeof(t))
#define N_GGNEW(n,t)      (t*)calloc((n),sizeof(t))

and later:

extern void *zmalloc(size_t);
extern void *zrealloc(void *, size_t, size_t, size_t);
extern void *gcalloc(size_t nmemb, size_t size);
extern void *gmalloc(size_t);
extern void *grealloc(void *, size_t);

I am not really into this memory allocation business (spoiled by the likes of Java and Swift), but what are we doing here? Why so many new versions? Why always so inspirational names? :slight_smile: Can these even work with each other? Should we try to harmonise?

1 Like

realloc/calloc/malloc do different things. I’m not sure about the other letters in front of the names or the macros though.

6 posts were split to a new topic: Potential language extension for graph object classes - motivation, design

It’s not even different mallocs - I think they are just macros or functions that wrap whatever malloc is around.

I realize that reliance on macros is passe and out of step with reasonable coding style today.

I will respectfully disagree with Stephen :slight_smile:

Vithanco, my background is mostly C/C++ and I still had a very similar reaction to you when learning the code base. In 2020 I deleted as much of lib/vmalloc as I could and tried to reduce other malloc duplication across the tree. Let me try to answer your questions…

Some of these have slightly different purposes. There’s the three library functions Mark noted, then the “g” prefixed wrappers that exit on failure and the “z” prefixed ones that return pre-zeroed memory. As for why the macros like N_NEW are repeated in various parts of the code base, I assume when this code was written #includes were somehow expensive and to be avoided.

My interpretation of the prefixes is “g/G” = “global”, “N_” = “new”, “z” = “zeroing”. This is terse, but pretty common in C code bases. I’ve seen the same named functions elsewhere.

Yes. They all allocate from the same heap, with the exception of lib/vmalloc (“vm” prefixed functions) which is an arena allocator. In the long term I would like to remove it completely.

Maybe. Some of these wrappers are useful. E.g. the zmalloc wrapper helps write more readable code. The “g” prefixed wrappers are also useful because many Graphviz allocations do not check the return value. None of this is really good practice, but we have to deal with the situation as it is.