Let’s look at the example from the docs:
SWL_GCArena gc = swl_gc_arena_new(<starting-capacity>);
int* foo = swl_gc_alloc(&gc, 5000, alignof(int), NULL);
int* bar = swl_gc_alloc(&gc, 16000, alignof(int), NULL);
int* baz = swl_gc_alloc(&gc, 3000, alignof(int), NULL);
// foo and baz are roots
SWL_GC_COLLECT(&gc, SWL_ROOT(foo), SWL_ROOT(baz));
// bar is gone, poof
If you try to access bar at the end you get a use after free. I am pretty sure if you tried to access foo again it would trigger the same problem, because it is a pointer directly to int and not an indirection. What happens if you pass a non-arena pointer to SWL_ROOT? What happens if you have multiple arenas and you mix and match them?There are many ways you could trivially shoot yourself in the foot in large program. It is a lot less “idiot-proof” than simple reference counting. The fact that you create each piece of memory and then have to manually pass it back to the root macro on each collection is very similar to the “malloc/free” dance we want to try and avoid.
The rooting issue is something I tried to tackle in my GC for rust[1]. Essentially making low level GC "idiot proof".
[1] https://coredumped.dev/2022/04/11/implementing-a-safe-garbag...