Si `malloc (0)` renvoie un pointeur non nul, puis-je le transmettre à `free`?

J’ai lu plus de discussions sur le comportement de malloc lorsque vous demandez un bloc de taille zéro.

Je comprends que le comportement de malloc(0) est défini par l’implémentation, et il est supposé renvoyer un pointeur nul ou un pointeur non nul auquel je ne suis pas censé accéder. (Ce qui est logique, car il n’y a aucune garantie que cela pointe vers une mémoire utilisable.)

Cependant, si un tel pointeur non nul est inaccessible, est-ce que je peux le transmettre free ? Ou est-ce illégal, puisque le pointeur que je reçois de malloc(0) peut ne pas pointer sur un bloc de mémoire réellement alloué?

Concrètement, le code suivant a-t-il un comportement bien défini:

 #include  #include  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? } 

La norme C99 (en fait WG14 / N1124. Projet de comité – 6 mai 2005. ISO / IEC 9899: TC2) à propos de malloc() :

Le pointeur a renvoyé des points au début (adresse d’octet le plus bas) de l’espace alloué. Si l’espace ne peut pas être alloué, un pointeur nul est renvoyé. Si la taille de l’espace demandé est zéro, le comportement est défini par l’implémentation: soit un pointeur nul est renvoyé, soit le comportement est comme si la taille présentait une valeur différente de zéro, sauf que le pointeur renvoyé ne devait pas être utilisé pour accéder à un object.

et à propos de free() :

Sinon, si l’argument ne correspond pas à un pointeur précédemment renvoyé par la fonction calloc, malloc ou realloc, ou si l’espace a été libéré par un appel à free ou realloc, le comportement n’est pas défini.

La norme IEEE 1003.1-2008 (POSIX), édition 2016 parle de free() :

La fonction free () doit libérer l’espace pointé par ptr; c’est-à-dire mis à disposition pour d’autres atsortingbutions. Si ptr est un pointeur nul, aucune action ne doit avoir lieu. Sinon, si l’argument ne correspond pas à un pointeur précédemment renvoyé par une fonction dans POSIX.1-2008 qui alloue de la mémoire comme par malloc (), ou si l’espace a été désalloué par un appel à free () ou realloc (), le comportement est indéfini.

Donc, quel que soit *alloc() , vous pouvez passer à free() .

Comme pour les implémentations actuelles de malloc() :

FreeBSD utilise le jemalloc fourni

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

Alors que libmalloc d’Apple fait

 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 [...] 

Le GLIBC modifie également la taille requirejse; il utilise un appel à cette macro avec la taille requirejse en octets comme paramètre pour aligner la taille sur une certaine limite ou simplement la taille d’allocation minimale:

 #define request2size(req) \ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ MINSIZE : \ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) 

Oui, en fait, vous devez le faire pour éviter une fuite de mémoire probable.

Le système malloc renvoie généralement un bloc de contrôle masqué dans l’espace immédiatement avant le pointeur, avec des informations telles que la taille de l’allocation. Si la taille d’allocation est zéro, ce bloc existe toujours et occupe la mémoire, si malloc retourne non nul.