Allocation dynamique : question vague

Allocation dynamique : question vague - C - Programmation

Marsh Posté le 24-06-2012 à 20:15:09    

Bonjour,
 
Je fais un peu de C à mes heures perdues et j'ai un bug qui revient souvent et auquel je ne comprends absolument rien.
Je n'ai malheureusement pas d'exemple pour le moment, ça apparait ou disparait de façon imprévisible (en tous cas pour moi c'est imprévisible  :pt1cable: ) quand je change des petites choses sans grand rapport dans mon code (mais si je le retrouve je poste le code, promis !)
 
Donc en fait ma question se résume à ça : A quoi peut être du un plantage lorsqu'on utilise free ?
J'ai d'abord pensé que free plantait lorsqu'on tentait de libérer un espace en mémoire qui n'est pas alloué au programme, j'ai donc testé le pointeur que je voulais free (ça peut être tout et n'importe quoi, j'ai eu ce problème avec des chaines de caractères, avec des listes chainées, ...) de la façon suivante : déjà j'ai vérifié que sa valeur ne changeait pas entre le malloc et le free, ensuite j'ai modifié la variable pointée juste avant de la free (dans la même fonction, vraiment juste avant !), le dernier caractère d'une chaine par exemple ou encore tous les éléments d'une structure, pour vérifier que cet espace en mémoire appartient bien à mon programme, jusque là aucun bug, et quand on arrive à free => "test.exe a cessé de fonctionner".
 
Grossièrement j'aimerais déjà savoir si ce type de bug est connu, sinon dès que je tombe dessus et que j'ai un exemple qui me le fait, je le poste.
Merci par avance de l'aide que vous pourrez m'apporter  :jap:  
 
Des fois que ça soit utile à savoir : je code avec code::blocks 10.05, sous windows 7.

Reply

Marsh Posté le 24-06-2012 à 20:15:09   

Reply

Marsh Posté le 24-06-2012 à 20:28:32    

un exemple de code qui peut planter :
 

Code :
  1. #include <stdlib.h>
  2. int main()
  3. {
  4. char * toto = malloc ( 10 );
  5. free ( toto );
  6. free ( toto );
  7. return 0;
  8. }


 
( pointeur déjà libéré ).
 
Tu peux également avoir un écrasement mémoire dans la zone qu'utilise malloc pour gérer la liste des segments alloués. Et là , comportement indéterminé, donc probablement plantage ( au moment où free parcours la liste chaînée pour trouver l'élément à libérer ).

Reply

Marsh Posté le 24-06-2012 à 20:29:24    

Ben, sans code c'est difficile à dire.
Sinon, oui un free sur une adresse inexistance / déjà supprimé ça fait planté le programme (segmentation fault), t'as pas un debugger sous la main histoire d'avoir le nom du signal d'arrêt ?


---------------
Perhaps you don't deserve to breathe
Reply

Marsh Posté le 24-06-2012 à 22:09:42    

empereur d'Esthar a écrit :

ça apparait ou disparait de façon imprévisible (en tous cas pour moi c'est imprévisible  :pt1cable: ) quand je change des petites choses sans grand rapport dans mon code
Salut


Tu décris ici une situation caractéristique d'un "comportement indéterminé".
Un comportement indéterminé se produit quand on fait faire au C une action qui n'est pas prévue par la norme. Ca peut-être (en vrac) aller lire une zone mémoire non allouée, lire un membre d'une union qui n'est pas le membre qui a été rempli, regarder la valeur d'une adresse qui ne t'appartient pas , etc etc.
Et donc le comportement indéterminé se traduit exactement comme son nom l'indique => il est impossible de prévoir le comportement du programme. Le programme peut fonctionner, il peut planter, il peut fonctionner le lundi et planter le mardi, il peut fonctionner plusieurs mois ou plusieurs années jusqu'à ce que tu le modifies de façon totalement mineure (comme rajouter un simple printf()). Bref c'est le pire des cas. On a vu un lanceur Ariane se crasher parce que le calculateur avait été testé dans l'hémisphère nord et quand on est passé dans l'hémisphère sud, le sinus est passé en négatif et le cas n'avait pas été prévu (enfin c'est une histoire que nous a raconté notre prof de maths mais je ne l'ai pas vérifiée)
 

empereur d'Esthar a écrit :

Donc en fait ma question se résume à ça : A quoi peut être du un plantage lorsqu'on utilise free ?


Généralement tu libères une zone non allouée ou déjà libérée.
 

empereur d'Esthar a écrit :

...ou encore tous les éléments d'une structure, pour vérifier que cet espace en mémoire appartient bien à mon programme


Ca ne veut rien dire. free() indique au système que la zone est libre mais ne la vide pas (pourquoi faire d'ailleurs puisqu'elle sera remplie quand ce sera nécessaire). Donc tu peux libérer ta zone, le contenu n'a pas changé. Mais il n'est plus à toi.
 
Pour éviter ce bug, 2 solutions
1) tu maitrises tes pointeurs à la perfection. Tu alloues quand il faut, tu sais en permanence quand c'est alloué et tu libères quand il faut. C'est la meilleure solution mais pas la plus facile
2) tu remplis systématiquement chaque pointeur libéré par NULL. En effet, free() détecte si le pointeur passé est à NULL et si c'est le cas, ne fait rien.

Code :
  1. char*c;
  2. ...
  3. c=malloc(...);
  4. ...
  5. free(c), c=NULL;


Ainsi si free() est de nouveau invoqué par erreur

Code :
  1. free(c), c=NULL;
  2. ...
  3. free(c), c=NULL;


Le second appel à free() sera ignoré.
C'est la solution de facilité parce qu'appeler free une fois de trop reste quand-même une action inutile et a donc l'inconvénient irréparable de ralentir inutilement ton code...
 

empereur d'Esthar a écrit :

Des fois que ça soit utile à savoir : je code avec code::blocks 10.05, sous windows 7.


Peut-être aussi que code::blocks est buggué (hypothèse qu'on ne peut pas écarter)...

Reply

Marsh Posté le 24-06-2012 à 22:20:52    

Ouais, euh, Code::block n'est qu'un IDE hein :o


---------------
Perhaps you don't deserve to breathe
Reply

Marsh Posté le 26-06-2012 à 18:42:58    

Citation :

On a vu un lanceur Ariane se crasher parce que le calculateur avait été testé dans l'hémisphère nord et quand on est passé dans l'hémisphère sud, le sinus est passé en négatif et le cas n'avait pas été prévu (enfin c'est une histoire que nous a raconté notre prof de maths mais je ne l'ai pas vérifiée)


 
J'ai du mal à y croire mais c'est amusant comme histoire ^^
 
Je me suis rendu compte hier qu'il m'était arrivé plusieurs fois de faire des mallocs avec un type de la forme "type*" au lieu de "type" (probablement du la prise d'une substance illicite avant de coder ...), j'ai pas encore vérifié dans mes autres projets si c'était la même connerie que j'avais faite mais en tous cas je re-regarderais à la lumière de ce que vous m'avez dit ici, merci :)

Reply

Marsh Posté le 26-06-2012 à 19:56:19    

Pour m'en être bouffé une tétrachiée d'erreur de ce type, je peux t'assurer que ce genre d'erreur resemble plus à un buffer overflow, qu'à une double libération d'un bloc mémoire. Il ne suffit de pas grand chose en fait: écrire un octet avant ou après le bloc = plantage quasi assuré au prochain malloc/free. D'autant plus la merde que l'endroit où ça va planter, ne sera pas l'endroit où le buffer overflow a eu lieu.

 

Le seul moyen vraiment sûr pour détecter ce genre d'erreur, c'est d'utiliser des outils type valgrind (ça excécute ton programme dans une machine virtuelle où tous les accès mémoires sont vérifiés). Il n'est malheureusement dispo que sous Linux, sous Windows il n'y a que des outils proprio (j'avais un jour testé purify: bah, ça vaut pas valgrind).


Message édité par tpierron le 26-06-2012 à 19:56:42
Reply

Marsh Posté le 26-06-2012 à 20:17:12    

boundschecker est pas mal, cher mais une version d'évaluation est possible.

Reply

Marsh Posté le 29-06-2012 à 21:11:09    

En effet c'est traitre comme erreur, ce pourquoi je vérifie ça assez rapidement. Cela dit ces outils paraissent intéressants, j'y penserais si un jour je suis à la limite de passer l'ordi par la fenêtre ^^

Reply

Marsh Posté le 30-06-2012 à 11:08:09    

Sve@r a écrit :


On a vu un lanceur Ariane se crasher parce que le calculateur avait été testé dans l'hémisphère nord et quand on est passé dans l'hémisphère sud, le sinus est passé en négatif et le cas n'avait pas été prévu (enfin c'est une histoire que nous a raconté notre prof de maths mais je ne l'ai pas vérifiée)


 
Heu non, la première "auto-destruction" d'Ariane 5 était dû à un bout de code (écrit en Ada) réutilisé d'Ariane 4 qui a déclenché une exception lors d'une conversion d'un flottant 64bits en entier 16bits. Sur un bout de code qui n'était utile qu'à la calibration au sol et qui n'avait plus de pertinence une fois le décollage lancé.
http://www.astrosurf.com/luxorion/ [...] e-v501.htm

Reply

Marsh Posté le 30-06-2012 à 11:08:09   

Reply

Marsh Posté le 01-07-2012 à 15:47:23    

si tu utilises visual, tu peux faire des appels à _CrtCheckMemory à des points clés, ca peut être assez utile et ca détecte très bien les dépassement de capacités.


---------------
last.fm
Reply

Marsh Posté le 25-07-2012 à 09:52:49    


Il existe des tonnes d'outils pour détecter ce genre de choses dont le plus connu est Valgrind -> http://valgrind.org/
 
Perso, ça fait des années que je me suis fait mon propre wrapper mémoire.
 
Ainsi, en développement et debug, tous mes appels sont détournés et si je veux libérer deux fois, même si je déborde un peu en écrivant, ma librairie me donnera le source, la fonction et la ligne de code qui pose problème.
 
En production, tous est désactivé et le programme peut tourner à fond les ballons

Reply

Marsh Posté le 25-07-2012 à 11:09:25    

Avoir sa propre bibliothèque pour gérer les allocations est une bonne chose, c'est certain .. Mais quand il est question de quelqu'un qui a du mal avec les concepts même d'allocation et les opérateurs ou fonctions à utiliser, c'est compliqué de lui recommander de se faire sa propre bibliothèque.


---------------
last.fm
Reply

Marsh Posté le 25-07-2012 à 14:20:20    

theshockwave a écrit :

Avoir sa propre bibliothèque pour gérer les allocations est une bonne chose, c'est certain .. Mais quand il est question de quelqu'un qui a du mal avec les concepts même d'allocation et les opérateurs ou fonctions à utiliser, c'est compliqué de lui recommander de se faire sa propre bibliothèque.


 
Sauf que je lui recommande Valgrind  :D  
 
Si il veut aller plus loin, il pourra se faire sa bibliothèque, mais c'est pour aller plus loin ça  :jap:

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed