Je réalise que l'exemple de code ci-dessous est quelque chose que vous ne devriez jamais faire. Ma question est juste l'un des intérêts. Si vous allouez un bloc de mémoire, puis déplacez le pointeur (un NON-NON), lorsque vous annouez la mémoire, quelle est la taille du bloc qui est traitée, et où est-il en mémoire? Voici l'extrait de code de contreveille:
#include <stdio.h> #include <string.h> int main(void) { char* s = malloc(1024); strcpy(s, "Some string"); // Advance the pointer... s += 5; // Prints "string" printf("%s\n", s); /* * What exactly are the beginning and end points of the memory * block now being deallocated? */ free(s); return 0; }
11 Réponses :
Oui, c'est un comportement indéfini. Vous libérez essentiellement un pointeur que vous n'avez pas MALLOC CODE>. P>
Pire encore pire, je m'attendrais à ce qu'elle écrase avec la plupart des Libs Malloc.
Comportement non défini signifie "tout peut arriver". De gonfler votre machine avec vous-même pour fonctionner correctement.
L'idiome commun que nous utilisons à mon travail pour un comportement non défini est «e-mail votre mère»
Vous ne pouvez pas transmettre un pointeur qui n'a pas été obtenu à partir d'un question 7.19 dans la FAQ C est pertinent pour votre question. P>
the Les conséquences d'invoquer le comportement non défini sont expliqués ici . P> MALLOC code>,
calloc code> ou
realloc code> à
gratuit code> ( sauf
null code>). p>
Merci. J'examine C Maintenant, après des années de ne pas la regarder. Je n'ai jamais rien fait avec elle au-delà des programmes de jouets pédagogiques. J'ai fait à la fois plus ou moins de comprendre les pointeurs, et cela semble me revenir ;-) Votre commentaire me rappelle que la variable du pointeur n'est pas la même chose que le pointeur, lui-même. Une fois que l'adresse stockée dans "S" est modifiée, il est toujours la même variable mais n'est plus le même pointeur.
Ce n'est pas le compilateur qui le fait, c'est la bibliothèque standard. Le comportement est indéfini. La bibliothèque sait qu'il a alloué l'original s code> à vous. Le
s + 5 code> n'est attribué à aucun bloc de mémoire connu de la bibliothèque, même s'il se trouve dans un bloc connu. Donc, cela ne fonctionnera pas. P>
Vous ne pouvez pas passer un pointeur que vous n'avez pas obtenu à partir de Comme une autre note, si vous vouliez tronquer le bloc, il existe un moyen légal de le faire: P> MALLOC code> (ou
calloc code> ou
realloc code> ...) sur
gratuit . Cela inclut des décalages dans des blocs que vous avez obtenus à partir de
MALLOC code>. Briser cette règle pourrait entraîner des tout ce qui se passe. D'habitude, cela finit par être la pire possibilité imaginable au pire moment possible.
#include <stdio.h>
#include <string.h>
int main() {
char *new_s;
char *s = malloc(1024);
strcpy(s, "Some string");
new_s = realloc(s, 5);
if (!new_s) {
printf("Out of memory! How did this happen when we were freeing memory? What a cruel world!\n");
abort();
}
s = new_s;
s[4] = 0; // put the null terminator back on
printf("%s\n", s); // prints Some
free(s);
return 0;
}
Ce que je me demande, c'est que les 5 octets dont l'emplacement en mémoire suit immédiatement la fin des 1024 octets d'origine, ou sont-ils juste laissés seuls? p> blockQuote>
les deux. Le résultat n'est pas défini, un compilateur est libre de faire l'un ou l'autre d'autres qu'ils aimeraient vraiment. Bien sûr (comme avec tous les cas de "comportement non défini") pour une plate-forme et un compilateur particulier, une réponse spécifique est une réponse spécifique, mais tout code reposant sur un tel comportement est une mauvaise idée. P>
Ajout aux réponses les plus formelles: je comparais la mécanique de ceci à une prise d'un livre dans la bibliothèque (MALLOC), puis en détachant quelques douzaines de pages avec la couverture (avancer le pointeur), puis en essayant de tenter. pour le retourner (gratuit). P>
Vous trouverez peut-être un bibliothécaire (implémentation de la bibliothèque MALLOC / GRATUIE) qui récupère un tel livre, mais dans beaucoup de cas, je m'attendrais à payer une amende pour une manipulation négligente. P>
Dans le projet de C99 (je n'ai pas la finale C99 à portée de main devant moi), il y a quelque chose à dire sur ce sujet: p>
La fonction libre provoque l'espace indiqué par
PTR code> pour être distribué, c'est-à-dire mis à disposition pour une allocation supplémentaire. Si
PTR code> est un pointeur nul, pas d'action se produit. Sinon, si l'argument ne correspond pas à un pointeur précédemment retourné par le
calloc code>,
malloc code> ou
realloc code> fonction ou si l'espace a été DefikeLocated par un appel à
Gratuit code> ou
realloc code>, le comportement est indéfini. P> blockQuote>
Dans mon expérience, un double libre ou gratuit du "pointeur" qui n'a pas été retourné via
Malloc code> entraînera une corruption de mémoire et / ou une crash, en fonction de votre
Malloc < / code> implémentation. Les personnes de sécurité des deux côtés de la clôture utilisaient ce comportement non une fois, afin de faire Diverses choses intéressantes au moins dans les premières versions du
Malloc CODE> MALLOC CODE>. P>
Version courte: C'est un comportement indéfini. P>
La plupart des implémentations se planteront parce qu'ils recherchent des données de suivi internes immédiatement avant le pointeur :)
Ou au moins corrompre le tas. Crashing immédiatement est le meilleur comportement possible ici.
Désolé, négligé de noter le crashing. Je suppose que j'avais oublié car d'autres personnes l'avaient mentionnée et j'essayais d'établir ce qui se passerait si un accident ne s'est pas produit. Pour que quelqu'un me descendit, à moins que vous n'ayez un problème différent avec ma réponse, veuillez reconsidérer, car je la possibilité de crash est en fait évidente de telle sorte que même je sache à ce sujet. Merci :-)
Ce n'est pas en train de vous descendre, cela descendit le commentaire. Ce n'est pas à propos de ce que vous savez, il s'agit de la qualité de ce que vous écrivez réellement. En outre, je pense que le reste de votre réponse est également faux; Comment vous attendez-vous à ce que l'implémentation de MALLOC rechercherait la longueur ou l'adresse finale pour S si vous lui donnez un pointeur différent de S + 5 qu'elle n'a jamais été allouée?
L'implémentation de la bibliothèque peut mettre une certaine structure de données avant em> le pointeur, il vous revient. Ensuite, dans GRATUIT () CODE> Il décrémente le pointeur pour obtenir à la structure de données qui lui indiquait comment placer la mémoire dans le pool libre. Donc, les 5 octets au début de votre chaîne "Certains" sont interprétés comme la fin du
struct code> utilisé par le
malloc () code> algorithme. Peut-être la fin d'une valeur de 32 bits, comme la taille de la mémoire allouée ou un lien dans une liste liée. Cela dépend de la mise en œuvre. Quels que soient les détails, cela va simplement planter votre programme. Comme Sinan souligne, si vous êtes chanceux! P>
signifie indéfini signifie indéfini b>. Vous seriez chanceux si cela bloque votre programme.
Il est un comportement indéfini dans la norme, vous ne pouvez donc pas compter sur quoi que ce soit. p>
N'oubliez pas que les blocs sont des zones de mémoire délimitées artificiellement et ne sont pas automatiquement arriver. Quelque chose doit garder une trace du bloc, afin de libérer tout nécessaire et rien de plus. Il n'y a pas de terminaison possible, comme des chaînes C, car il n'y a pas de valeur ni de combinaison de valeurs pouvant être garantie pour ne pas être à l'intérieur du bloc. P>
Dernier j'ai regardé, il y avait deux pratiques de base de la mise en œuvre. P>
On est de conserver un enregistrement séparé de blocs alloués, ainsi que l'adresse allouée. La fonction GRATUITE () lève le bloc pour voir quoi libérer. Dans ce cas, il risque simplement de ne pas le trouver et de ne rien faire tout simplement rien. Fuite de mémoire. Il n'y a cependant aucune garantie. P>
One est de conserver les informations de bloc dans une partie de la mémoire juste avant l'adresse de l'allocation. Dans ce cas, libre () utilise une partie du bloc sous forme de descripteur de bloc et en fonction de ce qui est stocké (ce qui pourrait être quelque chose), cela libérera quelque chose. Ce pourrait être un domaine trop petit ou une région trop grande. La corruption du tas est très probable. P>
Alors, je m'attendais à une fuite de mémoire (rien ne se libère) ou une corruption de tasse (trop est marquée librement, puis réaffectée). P>
Soyez intelligent ici ... Bien sûr, le comportement est indéfini en ce sens qu'il appartient au CRT / OS de décider quoi faire. Mais cela ne vous empêche pas de découvrir ce que fait votre plate-forme actuellement. P>
Un look rapide dans Windows CRT indique que Il y a des chèques consistant à tous ces chemins de code. Mais faire des choses différentes à la mémoire provoquera des chemins de code différents. D'où la vraie définition de non définie. P>
À un coup d'œil rapide, je peux voir qu'un bloc de mémoire alloué a un marqueur à la fin. Lorsque la mémoire est libérée, chaque octet est écrit avec un octet distinct. Le temps d'exécution peut faire un chèque pour voir si la fin du marqueur de bloc était écrasée et soulever une exception si oui. P>
Ceci est une posiblilité dans votre cas de mémoire de libération quelques octets dans votre bloc (ou en écrivant votre taille allouée). Bien sûr, vous pouvez vous tromper et écrire vous-même la fin du marqueur de bloc au bon endroit. Cela vous fera passer le chèque de CRT, mais comme le piste de code deviendra plus, le comportement plus indéfini se produit. Trois choses peuvent arriver: 1) absolument aucun préjudice, 2) la corruption de la mémoire dans le tas CRT, ou 3) une exception lancée par l'une des fonctions de gestion de la mémoire. P> gratuit () code> n'est pas un trou noir. À tout le moins, vous avez le code source CRT. Au-delà de cela, vous avez besoin du code source du noyau. P>
gratuit () code> DROITS à
HeapFree () Code> Utilisation d'un tas spécifique à CRT. Beoyond que vous êtes dans
rtlheapfree () code> puis dans l'espace système (ntoskrn.exe) avec le gestionnaire de mémoire
mm * () code>. P>.
Appel gratuit () sur un PTR qui n'a pas été attribué par Malloc ou ses frères est indéfini. strong> p>
La plupart des implémentations de MALLOC allouent une petite région d'en-tête (typiquement de 4 octets) immédiatement avant la rentrée du PTR. Ce qui signifie que lorsque vous avez alloué 1024 octets, Malloc réellement réservé 1028 octets. Lorsque l'on appelle gratuitement (PTR), si PTR n'est pas 0, il inspecte les données à PTR - Tailleof (en-tête). Certains allocators mettent en œuvre une vérification de la santé mentale afin de s'assurer que c'est un en-tête valide et qui pourrait détecter un mauvais PTR et affirmer ou sortir. S'il n'y a pas de vérification de la santé mentale, ou il passe à tort erroneusement, la routine libre agira sur toutes les données qui se trouvent dans l'en-tête. P>
+1, parce que j'ai appris à propos de quelque chose que je n'avais pas pensé.