Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If `malloc(0)` returns a non-null pointer, can I pass that to `free`?

I've been reading over discussions of how malloc behaves when you request a zero sized block.

I understand that the behavior of malloc(0) is implementation-defined, and it is supposed to either return a null pointer, or a non-null pointer that I am nonetheless not supposed to access. (Which makes sense, since there's no guarantee that it points to any usable memory.)

However, if a get such a nonaccessable non-null pointer, am I allowed to pass it to free in the usual way? Or is that illegal, since the pointer I get from malloc(0) may not point to an actual allocated block of memory?

Concretely, does the following code have well-defined behavior:

#include <stdio.h> #include <stdlib.h>  int main() {     int* x = (int*) malloc(0);     if (x == NULL) {         printf("Got NULL\n");         return 0;     } else {         printf("Got nonnull %p\n", x);     }     free(x); // is calling `free` here okay? } 
like image 370
pnkfelix Avatar asked Jun 02 '17 14:06

pnkfelix


People also ask

What happens if you malloc 0?

The result of calling malloc(0) to allocate 0 bytes is implementation-defined. In this example, a dynamic array of integers is allocated to store size elements. However, if size is 0, the call to malloc(size) may return a reference to a block of memory of size 0 instead of a null pointer.

Do you have to free malloc 0?

Yes, free(malloc(0)) is guaranteed to work.

Does malloc 0 return NULL?

[EDITED: it can sometimes allocate memory, see my next answer] The return value of malloc (0) is implementation specific: it can return NULL or a valid pointer (some unique value) as in your case but memory is not allocated!!!


2 Answers

The C99 standard (actually WG14/N1124. Committee Draft -- May 6, 2005. ISO/IEC 9899:TC2) says about malloc():

The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer is returned. If the size of the space requested is zero, the behavior is implementation defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object

and about free():

Otherwise, if the argument does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.

IEEE Std 1003.1-2008 (POSIX), 2016 Edition says about free():

The free() function shall cause the space pointed to by ptr to be deallocated; that is, made available for further allocation. If ptr is a null pointer, no action shall occur. Otherwise, if the argument does not match a pointer earlier returned by a function in POSIX.1-2008 that allocates memory as if by malloc(), or if the space has been deallocated by a call to free() or realloc(), the behavior is undefined.

So, whatever *alloc() returns, you can pass to free().

As for the current implementations of malloc():

FreeBSD uses the contributed jemalloc which does

void * je_malloc(size_t size) {     void *ret;     size_t usize JEMALLOC_CC_SILENCE_INIT(0);      if (size == 0)         size = 1;     [...] 

Whereas Apple's libmalloc does

void * szone_memalign(szone_t *szone, size_t alignment, size_t size) {     if (size == 0) {         size = 1; // Ensures we'll return an aligned free()-able pointer     [...] 

The GLIBC also changes the requested size; it is using a call to this macro with the requested size in bytes as the parameter to align the size to a certain boundary or simply the minimum allocation size:

#define request2size(req)                                       \     (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?         \     MINSIZE :                                                   \     ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) 
like image 166
apriori Avatar answered Sep 30 '22 18:09

apriori


Yes, in fact you must do so to avoid a probable memory leak.

The malloc system typically returns a hidden control block in the space immediately before the pointer, with information such as allocation size. If allocation size is zero, this block still exists and occupies memory, if malloc returns non-null.

like image 41
Malcolm McLean Avatar answered Sep 30 '22 20:09

Malcolm McLean