Standard C99 (actually WG14 / N1124. Committee draft - May 6, 2005 ISO / IEC 9899: TC2) speaks of malloc() :
The pointer returns the points to the beginning (low byte address) of the allocated space. If space cannot be allocated, the null pointer is back. If the size of the requested space is zero, the behavior is determined by the implementation: either a null pointer is returned, or the behavior is as if the size were some non-zero value, except that the returned pointer should not be used to access the object
and near free() :
Otherwise, if the argument does not match the pointer previously returned by the calloc, malloc, or realloc function, or if the space was freed by calling free or realloc, the behavior is undefined.
IEEE Std 1003.1-2008 (POSIX), 2016 release talks about free() :
The free () function must call the space pointed to by ptr to be freed; that is, available for further distribution. If ptr is a null pointer, no action will be taken. Otherwise, if the argument does not match the pointer previously returned by the function in POSIX.1-2008 that allocates memory as if it were malloc (), or if the space was freed up by calling free () or realloc (), the behavior is undefined.
So, no matter what *alloc() returns, you can go to free() .
Regarding current malloc() implementations:
FreeBSD uses the provided jemalloc, which makes
void * je_malloc(size_t size) { void *ret; size_t usize JEMALLOC_CC_SILENCE_INIT(0); if (size == 0) size = 1; [...]
While Apple libmalloc does
void * szone_memalign(szone_t *szone, size_t alignment, size_t size) { if (size == 0) { size = 1;
GLIBC also changes the requested size; it uses a call to this macro with the requested size in bytes as a parameter to align the size with a certain border or just the minimum allocation size:
#define request2size(req) \ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ MINSIZE : \ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)