The malloc stuff is what I've had to deal with myself. They've gone back and forth about whether certain things are allowed and how they're defined, like realloc with size 0, aligned_alloc with an alignment that's not a multiple of the size and several other things for those.
Conversation
Does realloc(p, 0) do the equivalent of malloc(0) and then frees p if successful? Does it simply free p? Is it undefined? Who even knows anymore, because they changed it too many times (literally at least 3 times) and while I think it's undefined now it's very commonly used...
3
3
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.
1
2
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.
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
Show replies

