Ma mémoire prend la fuite!

  • Je ne vous fait pas une tartine sur les problèmes de gestion mémoire en C.
    • Si vous avez approché un compilateur C un jour de votre vie, vous savez de quoi je parle.
  • Pour prévenir les problèmes de fuite mémoire, il existe plusieurs méthodes.


Je ne fais rien
  • Ne rigolez pas, un OS bien conçu est censé vous rendre la mémoire à la sortie de votre programme.
  • Bon alors, on fait comme ça ?
    • Non, on ne fait pas comme ça. On passe toujours un coup de balai avant de quitter un programme, question de savoir-vivre et d'éducation.
    • Il y a également le fait qu'on ne sait jamais vraiment où le programme finira par tourner, ni si l'OS réussira réellement à récuperer toute la mémoire.


J'écris mon gestionnaire mémoire
  • Allez, on l'a tous fait un jour ou l'autre.
    • Ou comment finir avec un wrapper de malloc/free plus ou moins élaboré, qui génère de jolies listes d'alllocations/libérations.
  • Ce n'est pas forcément une mauvaise idée. C'est surtout délicat à gérer pour toutes sortes de raisons (je ne développe pas, si vous ne comprenez pas, essayez de faire le votre).
  • L'insensé tenant vraiment à explorer la Voie de l'Insomnie pourra toujours commencer par : man malloc_hook.


J'utilise mtrace
  • Et c'est la prise de conscience sur un titre judicieusement choisi.



mtrace, principe et utilisation

Prérequis
  • Une libc GNU.
  • Un compilateur GNU.


Principe
  • Le principe consiste à intercepter les appels à malloc et à free, et à tenir registre des allocations/libérations de mémoire.
  • Pour cela, vous initialiserez le wrapper de la libc avec mtrace() , et vous appellerez en sortie muntrace().


Utilisation
  • Il suffit d'inclure mcheck.h et vous pourrez utiliser les deux fonctions requises.
    • mtrace : avant tout malloc().
    • muntrace : après le dernier free().
  • Vous aurez également besoin d'une variable shell, pour indiquer où écrire le fichier de log.
    • export MALLOC_TRACE = /path/to/log.txt
  • Une autre variable shell peut être utilisée: MALLOC_CHECK
    • Normalement, son usage est d'indiquer le niveau de log.
    • export MALLOC_CHECK = 2 : fait planter le programme si erreur malloc (je tenais à vous faire partager cette découverte).
  • Un script Perl (mtrace) pour mettre en forme le fichier de log.



L'exemple tant attendu

Source pour nos essais
/* mtrace.c */

#include <stdio.h>
#include <stdlib.h>
#include <mcheck.h>

int main(void)
{
  mtrace();

  char *freed = malloc(1024);
  char *leaked = malloc(1024);

  if (freed) free(freed);

  muntrace();
  return 0;
}

  • Pour compiler ce source, rien de spécial.
    • gcc -g -Wall mtrace.c -o mtrace
    • N'oubliez pas -g pour avoir les symboles dans la sortie de mtrace.
  • Et pour le lancer:
    • MALLOC_TRACE=/tmp/mtrace.log ./mtrace
    • Le prompt revient, pas de plantages, donc, pas de problèmes.
    • Vraiment ?


Utilisation du script Perl mtrace
  • Tout d'abord, voyons à quoi ressemble le fichier log.

~test$ cat /tmp/mtrace.log 
= Start
@ ./mtrace:[0x40060f] + 0x1ea7460 0x400
@ ./mtrace:[0x40061d] + 0x1ea7870 0x400
@ ./mtrace:[0x400631] - 0x1ea7460
= End

  • De ce qui précède, on peut deviner aisément que le bloc mémoire situé à 0x1ea7870 n'a pas été libéré.
    • Nous allons cependant rendre plus parlant ce fichier.
  • Le script mtrace s'invoque avec en paramètres l'exécutable à analyser (pour ses symboles), et le fichier log.

~test$ MALLOC_TRACE="/tmp/mtrace.log" mtrace ./mtrace /tmp/mtrace.log 

Memory not freed:
-----------------
           Address     Size     Caller
0x0000000001cb6870    0x400  at /home/jseb/test/mtrace.c:12

  • Voila qui est plus parlant.
    • La ligne indiquée correspond au malloc() sans free() correspondant.



mtrace n'est cependant pas Dieu le Père Tout Puissant

  • mtrace ne vous protégera bien sûr pas des écrasements mémoire durant l'exécution de votre programme.
  • De même, les problèmes de gestion mémoire ne seront pas détectés. Il peut cependant vous signaler des free multiples.
  • Sa facilité d'emploi devrait toutefois inciter tout codeur un tant soit peu consciencieux à l'utiliser.
  • Une alternative consiste à laisser tomber malloc et free, mais je laisse ça aux gens qui ont des problèmes de mémoire.