The overflow scenario should be treated the same as the out-of-memory scenario and also return null. The hypothetical result of the addition would always be larger than `heap_end`.
Suppose you allocate heap at the far end of the address space, then all out-of-memory events suddenly become overflows.
> The main limitation of a bump allocator is that it can only reuse deallocated memory after all allocations have been freed.
It can do better, in `dealloc` you can use `ptr` and `layout` to check if the allocation is at the end of the allocated region. If it is, `bump.next` can be reduced by `layout.size()`. This is optimal for lifo/stack style allocation patterns.
Alignment complicates implementation since precise information on the previous value of `bump.next` is lost. There are way to solve this, for example by always padding to some maximum alignment, or writing the padding size in the padding.