Débogage avancé/Travail pratique/Allocation: 0, Libération: 1

Leçons de niveau 17
Une page de Wikiversité, la communauté pédagogique libre.
Début de la boite de navigation du travail pratique
Allocation:0, Libération 1
Image logo représentative de la faculté
T.P. no 4
Leçon : Débogage avancé

TP de niveau 17.

Précédent :Double libération
Suivant :Débogage à la volée
En raison de limitations techniques, la typographie souhaitable du titre, « Travail pratique : Allocation:0, Libération 1
Débogage avancé/Travail pratique/Allocation: 0, Libération: 1
 », n'a pu être restituée correctement ci-dessus.


But de ce TP[modifier | modifier le wikicode]

Il existe deux principales façons d'allouer de la mémoire dans un programme: dans la pile (les variables locales) et dans le tas (malloc/free). Un pointeur dans un langage comme C ou C++ peut donc pointer de la mémoire valide mais qui n'a jamais été allouée avec un malloc.

La fonction free() sert exclusivement à libérer de la mémoire allouée dans le tas avec malloc, calloc ou realloc.

Le code dans ce TP utilise un tableau alloué dynamiquement dans la pile. Ce tableau ne doit surtout pas être libéré. Cela n'a pas de sens du point de vue de la mémoire.

Le code à déboguer[modifier | modifier le wikicode]

Créer un fichier bug_stackallocthenfree.c contenant le code suivant.

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

unsigned int SIZE = 100;

// le tableau en argument a été alloué dans la pile, pas avec
// malloc. free ne peut pas être appellé dessus. p est passé avec des
// argument de type C11+

void fibon(const unsigned int size, unsigned int p[static size]) {
  for (unsigned int i = 0; i < size; i++)
    if (i < 2)
      p[i] = i;
    else
      p[i] = p[i - 1] + p[i - 2];
  free(p); // BUG !
}

// Notation C11+ pour les arguments du main
int main(int argc, char *argv[static argc + 1]) {
  if (argc == 2)
    SIZE = atoi(argv[1]);
  assert(SIZE > 2);

  unsigned int p[SIZE];
  assert(p != NULL);

  fibon(SIZE, p);

  return EXIT_SUCCESS;
}

Les consignes[modifier | modifier le wikicode]

  1. Compiler le programme. Un analyseur statique récent détecte le bug
  2. Lancer le programme bug_stackallocthenfree
  3. Lancer le programme avec Valgrind. Valgrind vous indique que votre variable a été allouée dans la frame de la fonction main (les variables locales de main) mais il ne vous indique pas laquelle.
  4. Relancer le programme avec Valgrind en demandant à ce dernier de s'arrêter avant le début de l'exécution pour vous laisser vous connecter avec GDB. Connecter GDB. Continuer l'exécution. Remonter dans la pile d'appel et afficher l'adresse de la variable p.
  5. Recompiler avec ASan. Lancer le programme. ASan indique que ce qui est libéré vient de la pile
  6. Lancer la commande ulimit -s pour obtenir la taille maximum de votre pile (probablement 8192 Kio, soit 8 Mio). Lancer le programme avec comme argument une valeur au moins 256 fois plus grandes (2097152 = 8192 * 1024/4 car *1024 pour avoir la taille en octet /4 car un entier est sur 4 octets). ASan détecte cette fois un stack overflow. le tableau en variable local est trop grand pour rentrer dans la pile.