Aller au contenu

Débogage avancé/Travail pratique/Allocation dans la pile

Une page de Wikiversité, la communauté pédagogique libre.
Début de la boite de navigation du travail pratique
Allocation dans la pile
Image logo représentative de la faculté
T.P. no 7
Leçon : Débogage avancé
Précédent :Observation à la loupe
En raison de limitations techniques, la typographie souhaitable du titre, « Travail pratique : Allocation dans la pile
Débogage avancé/Travail pratique/Allocation dans la pile
 », n'a pu être restituée correctement ci-dessus.

Pour éviter le tourbillon de Charybde des allocations dynamique dans le tas (heap), certains programmeurs aventureux ou programmeuses aventureuses sont prêts à se jeter dans la gueule du monstre Scylla des allocations dynamique dans la pile (stack).

Ils doivent alors de garantir que l'adresse de l'allocation ne sera jamais utilisée après la fin de l'exécution de la fonction, puisque cette fin va entrainer la libération automatique de l'allocation.

Côté débogage, le problème est que la pile est librement manipulable. Il est possible d'y lire et d'y écrire partout ! Et du coup tous les outils deviennent beaucoup plus difficiles à exploiter.

Le code à déboguer

[modifier | modifier le wikicode]

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

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

typedef struct elem {
  struct elem *next;
} Elem;

// Patron commun en Python mais délétère en C
// NB: l'arithmétique sur les pointeurs suffit empêcher l'apparition de
// l'avertissement par le compilateur.
Elem *Elem_new() {
  Elem a = {.next = NULL}; // BUG: Elem *a = malloc(sizeof(Elem));
  Elem *p = &a;
  p++; // pour tromper le linter de votre IDE
  p--; // pour tromper le linter de votre IDE
  return p; // BUG: return a;
}

int list_length(Elem *h) {
  long long int l = 0;
  while (h != NULL) {
    h = h->next;
    l++;
  }
  return l;
}

int main() {
  Elem *a = Elem_new();
  Elem *b = Elem_new();
  a->next = b; // the code should fail here
  Elem *head = a;

  printf("list length: %d", list_length(head));
  return EXIT_SUCCESS;
}

Le code bug_allocinstack.c reproduit un schéma classique de la programmation en Python. Mais, pour allouer tous ses objets, Python utilise le tas (malloc) ! Même si la syntaxe est identique, Python ne fait pas du tout la même chose que ce code qui crée son objet dans la pile de la fonction.

  1. Compiler le programme. Les deux lignes p++,p-- sont peut-être suffisantes pour désorienter votre linter, mais probablement pas l'analyseur statique d'un compilateur récent.
  2. Exécuter le programme. Suivant le code généré, il peut boucler à l'infini.
  3. Exécuter le programme avec Valgrind. Vous n'aurez pas beaucoup plus d'indications.
  4. Compiler et exécuter le programme avec ASan.
  5. TODO: Exécuter le programme avec gdb et détecter avec un watchpoint qui modifie dans le champ next.
'