The previous `_realloc_r` implementation would leak the original memory block (`ptr`) when the in-place `SetPtrSize` call failed and a new block had to be allocated.
This change also adds correct handling for `realloc(ptr, 0)`, which should free the block and return `NULL`.