Free (ptr) où ptr est NULL est-il corrompu?

112

Théoriquement, je peux dire que

free(ptr);
free(ptr); 

est une corruption de mémoire puisque nous libérons la mémoire qui a déjà été libérée.

Mais si

free(ptr);
ptr=NULL;
free(ptr); 

Comme le système d'exploitation se comportera d'une manière indéfinie, je ne peux pas obtenir une analyse théorique réelle de ce qui se passe. Quoi que je fasse, cette mémoire est-elle corrompue ou non?

La libération d'un pointeur NULL est-elle valide?

Vijay
la source
1
pas sûr de la norme gratuite C, mais en C ++, delete (NULL) est parfaitement valide, donc je suppose que free (NULL) devrait également l'être.
Priyank Bolia
14
@Pryank: delete NULLn'est pas valide en C ++. delete peut être appliqué à des valeurs de pointeur nul de type concret, mais pas à NULL. delete (int*) NULLest légal, mais pas delete NULL.
AnT
donc cela signifie que si un pointeur pointe vers NULL gratuitement, cela n'effectue rien. Cela signifie-t-il !!!!!! à chaque fois dans notre codage si vous voulez libérer une mémoire, vous pouvez simplement remplacer un free (ptr) par ptr = NULL?
Vijay
3
Non. Si ptrpointe vers la mémoire et que vous ne l'appelez pas free, la mémoire fuira. Le paramétrer sur NULLperd simplement votre maîtrise de la mémoire et des fuites. Si ptr cela se produitNULL , l'appel freeest une non-opération.
GManNickG
1
@benjamin: Hein? Ce qui vous a amené à conclure que vous pouvez remplacer free(ptr)par ptr = NULL. Personne n'a rien dit de tel.
AnT

Réponses:

224

7.20.3.2 La freefonction

Synopsis

#include <stdlib.h> 
void free(void *ptr); 

La description

La freefonction provoque la ptrdésallocation de l'espace pointé par , c'est-à-dire la mise à disposition pour une allocation ultérieure. Si ptrest un pointeur nul, aucune action ne se produit.

Voir ISO-CEI 9899 .

Cela étant dit, en regardant différentes bases de code dans la nature, vous remarquerez que les gens font parfois:

if (ptr)
  free(ptr);

C'est parce que certains runtimes C (je me souviens bien que c'était le cas sur PalmOS) plantaient lors de la libération d'un NULLpointeur.

Mais de nos jours, je pense qu'il est prudent de supposer que free(NULL)c'est un non conformément aux instructions de la norme.

Gregory Pakosz
la source
29
Non, ptr = NULL n'est pas un remplacement gratuit (ptr), les deux sont complètement différents
Prasoon Saurav
7
NON, cela signifie que free(ptr)ptrest nul n'a aucun effet secondaire. Mais dans tous les cas, chaque mémoire allouée en utilisant malloc()ou calloc()doit être libérée par la suite en utilisantfree()
Gregory Pakosz
4
ptr = NULL garantit que même si vous appelez accidentellement free (ptr), votre programme ne fera pas de segment.
Prasoon Saurav
2
Veuillez noter que bien que le standard C dise que c'est un no-op, cela ne signifie pas que chaque bibliothèque C le gère comme ça. J'ai vu des plantages gratuits (NULL), il est donc préférable d'éviter d'appeler le gratuit en premier lieu.
Derick
6
@WereWolfBoy il veut dire éviter free(NULL)en testant le pointeur NULLavant d'appelerfree()
Gregory Pakosz
22

Toutes les versions conformes aux normes de la bibliothèque C traitent free (NULL) comme un no-op.

Cela dit, à un moment donné, il y avait des versions de free qui plantaient sur free (NULL), c'est pourquoi vous pouvez voir certaines techniques de programmation défensives recommandées:

if (ptr != NULL)
    free(ptr);
R Samuel Klatchko
la source
8
-1 [citation nécessaire]. Changer de style de code à cause d'une théorie d'une implémentation archaïque par ouï-dire est une mauvaise idée.
Tomas
41
@Tomas - Je n'ai jamais recommandé de changer de style, j'ai simplement expliqué pourquoi vous pouvez toujours voir cette recommandation dans certains styles.
R Samuel Klatchko
5
@Tomas 3BSD ( winehq.org/pipermail/wine-patches/2006-October/031544.html ) et PalmOS pour deux (2e main pour les deux).
Douglas Leeder
7
@Tomas: le problème était dans des choses comme la version 7 Unix. Quand j'apprenais, free (xyz) où xyz == NULL était une recette pour un désastre instantané sur la machine où j'ai appris (ICL Perq exécutant PNX, qui était basé sur la version 7 Unix avec quelques extras System III). Mais je n'ai pas codé de cette façon depuis longtemps.
Jonathan Leffler
2
NetWare plante aussi lors de la libération de NULL ... (vient de déboguer un crash dessus ...)
Calmarius
13

Si ptr est NULL, aucune opération n'est effectuée.

dit la documentation.

Michael Krelin - hacker
la source
voulez-vous dire que libre ne fera rien?
Vijay
2
benjamin, c'est exactement ce que cela signifie. À quoi vous attendez-vous qu'il exécute s'il est conscient de la nullité de l'argument?
Michael Krelin - hacker
12

Je me souviens avoir travaillé sur PalmOS où free(NULL)s'est écrasé.

jlru
la source
4
Intéressant - cela fait une deuxième plate-forme (après 3BSD) qui plante.
Douglas Leeder
2
Si je me souviens bien, sur Palm, la bibliothèque standard C n'existait pas. Au lieu de cela, il y avait un fichier d'en-tête pour la plupart non pris en charge qui mappait les appels de bibliothèque standard via le SDK Palm OS. Beaucoup de choses ont agi de manière inattendue. Le crash NULLétait l'une des grandes différences de fonctionnement de la boîte à outils Palm par rapport à la bibliothèque standard.
Steven Fisher
8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

Vous pouvez supprimer en toute sécurité un pointeur NULL. Aucune opération ne sera effectuée dans ce cas, en d'autres termes free () ne fait rien sur un pointeur NULL.

Prasoon Saurav
la source
8

Utilisation recommandée:

free(ptr);
ptr = NULL;

Voir:

man free

     The free() function deallocates the memory allocation pointed to by ptr.
     If ptr is a NULL pointer, no operation is performed.

Lorsque vous réglez le pointeur sur NULLaprès, free()vous pouvez le rappeler free()et aucune opération ne sera effectuée.

stefanB
la source
3
Cela aide également à repérer les défauts de segmentation avec un débogueur. Il est évident que segfault à p-> do () avec p = 0 est quelqu'un utilisant un pointeur libéré. Moins évident quand vous voyez p = 0xbfade12 dans le débogueur :)
neuro
6

free(NULL)est parfaitement légal en C, ainsi que delete (void *)0et delete[] (void *)0sont légaux en C ++.

BTW, libérer de la mémoire deux fois provoque généralement une sorte d'erreur d'exécution, donc cela ne corrompe rien.

n0rd
la source
2
delete 0n'est pas légal en C ++. deletenécessite explicitement une expression de type pointeur. Il est légal de s'appliquer deleteà une valeur de pointeur nul typée, mais pas à 0(et pas à NULL).
AnT
1
Vous ne pouvez pas non plus supprimer void*: P Quels destructeurs doit-il exécuter?
GManNickG
1
@GMan: Vous pouvez supprimer void *tant qu'il s'agit d'un pointeur nul.
AnT
OK très bien. J'ai oublié que nous ne traitons que de null.
GManNickG
ne corrompent généralement rien, mais ce n'est pas garanti. ASLR rend cela plutôt improbable, mais toujours pas impossible: buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - ici, si vous êtes malchanceux, buf2 a exactement la même adresse que buf1, et vous avez accidentellement libéré buf1 deux fois, donc le 2ème libre de buf1 vous avez en fait libéré buf2 silencieusement, sans casse toute erreur (immédiate) / crash / peu importe. (mais vous aurez probablement toujours un crash la prochaine fois que vous essayez d'utiliser buf2 - et ce scénario est très peu probable si vous utilisez ASLR)
hanshenrik
3

free(ptr)est sauf en C si ptrest NULL, cependant, que la plupart des gens ne savent pas est que NULLn'a pas besoin d' être égal à 0. J'ai un bel exemple de la vieille école: Sur la C64, sur l' adresse 0, il y a un IO-Port. Si vous avez écrit un programme en C accédant à ce port, vous auriez besoin d'un pointeur dont la valeur est 0. La bibliothèque C correspondante devrait faire la distinction entre 0 et NULLalors.

Sincères amitiés.

andi8086
la source
Fait intéressant, m'a pris par surprise. Je me suis senti obligé de faire un voyage autour des questions / réponses du pointeur NULL.
arthropode
0

pas de corruption de mémoire, mais le comportement dépend de la mise en œuvre. En règle générale, ce devrait être un code juridique.

Pavel Radzivilovsky
la source
-3

ptr pointe vers un emplacement mémoire, disons 0x100.

Lorsque vous libérez (ptr), vous autorisez essentiellement l'utilisation de 0x100 par le gestionnaire de mémoire pour d'autres activités ou processus et, en termes simples, il s'agit de la désallocation des ressources.

Lorsque vous faites ptr = NULL, vous faites pointer ptr vers un nouvel emplacement (ne vous inquiétez pas de ce qu'est NULL). En faisant cela, vous avez perdu la trace des données de la mémoire 0x100. C'est ce qui est une fuite de mémoire.

Il n'est donc pas conseillé d'utiliser ptr = NULL sur un ptr valide.

Au lieu de cela, vous pouvez effectuer une vérification en toute sécurité en utilisant:

if (ptr! = NULL) {libre (ptr);}

Lorsque vous libérez (ptr) où ptr pointe déjà vers NULL, il n'effectue aucune opération.

Kishanp
la source