58 votes

Comment free et malloc fonctionnent-ils en C?

J'essaie de comprendre ce qui se passerait si j'essayais de libérer un pointeur "du milieu", par exemple, regardez le code suivant:

 char *ptr = (char*)malloc(10*sizeof(char));

for (char i=0 ; i<10 ; ++i)
{
	ptr[i] = i+10;
}
++ptr;
++ptr;
++ptr;
++ptr;
free(ptr);
 

Je reçois un plantage avec une erreur d’exception non gérée. Je veux comprendre pourquoi et comment free fonctionne pour que je sache non seulement l'utiliser, mais aussi que je sois capable de comprendre les erreurs et les exceptions étranges et de mieux déboguer mon code

Merci beaucoup

105voto

Jason Williams Points 31901

Lorsque vous malloc un bloc, il alloue un peu plus de mémoire que vous avez demandé. Cette mémoire supplémentaire est utilisé pour stocker des informations telles que la taille du bloc alloué, et un lien à l'autre libre/bloc utilisé dans une chaîne de blocs, et parfois certains "protection des données" qui permet au système de détecter si vous écrivez après la fin de votre bloc alloué.

Lorsque vous libérer de votre pointeur, il utilise cette adresse pour trouver l'information spéciale, il a ajouté au début de votre bloc alloué. Si vous passez à une autre adresse, elle aura accès à la mémoire qui contient les ordures, et donc son comportement est indéfini (mais qui le plus souvent sera le résultat d'un crash)

25voto

DigitalRoss Points 80400

Vous savez probablement que vous êtes censé passer exactement le pointeur que vous avez reçu.

Parce que free() n'est pas d'abord de savoir de quelle taille est votre bloc est, il a besoin d'informations supplémentaires afin d'identifier le bloc d'origine à partir de son adresse et de revenir ensuite à une liste libre. Il tentera également de fusionner les petites libéré des blocs avec les voisins afin de produire une plus précieux grand bloc libre.

En fin de compte, l'allocation doit avoir des métadonnées sur votre bloc, à un minimum, il sera nécessaire d'avoir stocké la longueur de quelque part.

Je vais décrire trois façons de le faire.

  • Un endroit évident serait de stocker juste avant de le pointeur retourné. Il pourrait allouer un bloc de quelques octets de plus que ce qui est demandé, magasin de la taille dans le premier mot, puis de retour pour vous un pointeur vers le deuxième mot.

  • Une autre façon serait de garder une carte distincte décrivant au moins la longueur de blocs alloués, à l'aide de l'adresse comme une clé.

  • Une mise en œuvre pourrait tirer des informations à partir de l'adresse et une carte. Le noyau BSD 4.3 allocateur (qui s'appelait, je crois, la "McKusick-Karel allocateur") rend la puissance de deux allocations pour les objets de moins de la taille de la page et ne conserve que par la taille de page, en faisant toutes les allocations à partir d'une page donnée, d'une taille unique.

Il serait possible qu'avec certains types de la deuxième et probablement n'importe quelle sorte de troisième type de l'allocation pour vraiment détecter que vous avez avancé le pointeur et DTRT, bien que je doute que toute la mise en œuvre de brûler le moteur d'exécution pour le faire.

10voto

Zeograd Points 869

La plupart (si pas tous) de la mise en œuvre sera la recherche de la quantité de données afin de libérer de quelques octets avant le pointeur de la manipulation. Faire une wild - free conduira à la mémoire de la carte de la corruption.

Si votre exemple, lorsque vous allouez 10 octets de mémoire, le système de réserve, disons, 14. Le premier 4 contient la quantité de données que vous avez demandé (10), puis la valeur de retour de l' malloc est un pointeur vers le premier octet de données non utilisés dans le 14 alloué.

Lorsque vous appelez free sur ce pointeur, le système de recherche de 4 octets en arrière pour savoir qu'il allouée à l'origine de 14 octets pour qu'il sache combien gratuit. Ce système vous empêche de fournir la quantité de données pour libérer comme un paramètre supplémentaire à l' free lui-même.

Bien sûr, d'autres de la mise en œuvre de l' malloc/free pouvez choisir la façon d'atteindre cet objectif. Mais généralement, ils ne supportent pas d' free sur un pointeur différent de ce qui a été renvoyé par malloc ou l'équivalent de la fonction.

8voto

Petros Points 674

À partir de http://opengroup.org/onlinepubs/007908775/xsh/free.html

Le free() fonction provoque l'espace pointé par ptr pour être libéré; c'est, mis à disposition pour plus d'allocation. Si ptr est un pointeur null, aucune action ne se produit. Sinon, si l'argument ne correspond pas à un pointeur retourné plus tôt par le calloc(), la fonction malloc(), realloc() ou valloc() de la fonction, ou si l'espace est libéré par un appel à free() ou realloc(), le comportement est indéfini. Toute utilisation d'un pointeur qui se réfère à l'espace libéré provoque un comportement indéterminé.

7voto

sharptooth Points 93379

C'est un comportement indéfini - ne le faites pas. Seuls les pointeurs free() obtenus à partir de malloc() , ne les ajustez jamais auparavant.

Le problème est que free() doit être très rapide, il n'essaie donc pas de trouver l'allocation à laquelle appartient votre adresse ajustée, mais plutôt de renvoyer le bloc exactement à l'adresse ajustée dans le tas. Cela conduit à un comportement indéfini - généralement une corruption de tas ou un crash du programme.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X