That's what glibc does but it's in violation of POSIX and also the C standard before they basically gave up and said you shouldn't do it anymore. The proper way to handle it is matching malloc(0) rather than making a realloc-specific special case that's actively dangerous.
Conversation
The various *BSD malloc implementation match malloc(0) so that's what Android does and therefore is what LLVM ended up doing IIRC.
glibc has the weird special case of realloc(p, 0) meaning free(p) unless p is NULL and then it means malloc(0) like it would with a normal approach.
2
1
It's very common for programs to trigger this by not handling 0 size as a special case and I wouldn't be surprised if they often ended up with a double-free with glibc malloc. It's better to leak memory if something expects it to free, which is non-portable GNU behavior.
1
1
Even if your goal is glibc compatibility, the malloc implementation should really always treat it as malloc(0).
Also, even though the C standard implies you can return NULL for malloc(0), you can't really do that, and it's dangerous since stuff dereferences with large offsets.
2
Best way to handle malloc(0) is returning a unique pointer to PROT_NONE memory so that accessing it will fault, which retains compatibility and also deals with programs ending up with 0 due to screwing up a calculation. Sometimes end up with 0 in overflow situations, etc.
1
Is it necessary to return a different pointer each time?
1
Yes, it still has to be a pointer to an allocation with a unique address and it probably also still has to be aligned for strict compatibility / standards compliance so you actually have to waste 16 bytes of virtual memory, not that it has any real cost (not very common anyway).
1
Programs often don't special case 0-size allocations and end up using malloc(0) at the start of a loop, the end of a loop, or just when handling that kind of input. The glibc approach tends to lead to double frees in those special cases. NULL tends to cause aborts or crashes.
1
Most malloc implementations just round 0 up to 16 and give out usable memory for it, for which they'll return 16 via the non-standard malloc_usable_size too.
malloc_usable_size API is broken since compilers infer the size from what you passed to malloc and optimize based on it.
1
_FORTIFY_SOURCE and -fsanitize=object-size (part of UBSan) will also add bounds checks based on the size and while they aren't smart enough to handle malloc(n) with a non-constant n, they will infer the size for checks if n is constant early on during compilation / optimization.
1
Anyway, malloc_usable_size as a way to use more memory than you requested is broken in general, not just for malloc(0). Similar issue for ksize in the kernel although it's not as broken unless you add alloc_size attributes to kmalloc, etc yourself since they aren't called malloc.

