A simple pool is much safer, but can suffer from fragmentation. It is a double linked list of memory fragments.
This produces an overhead on each memory allocation, you attach a header to each allocation. So each alloc consumes requested memory + header size bytes of memory.
When you free a block of memory, you look at the last and next blocks. If either of those is free you join this allocation to it... kind of hard to explain.
Note that the memory overhead caused by link pointers can be safely eliminated through the proper use of unions and type punning.