Segmentation fault : diagnostiquer un crash sous Linux
Une segmentation fault (segfault) signifie qu’un programme a essaye d’acceder a une zone mémoire qu’il n’a pas le droit de toucher. Le noyau detecte l’acces illegal, tue le processus et affiche Segmentation fault (core dumped). Le message ne dit pas pourquoi le programme a echoue ; il dit que le noyau a coupe l’execution. Diagnostiquer une segfault demande de lire le core dump, pas de deviner la cause.
Sommaire
- Comprendre ce que la segfault mesure
- Etape 1 : activer les core dumps
- Etape 2 : lire le backtrace avec gdb
- Etape 3 : identifier la cause la plus probable
- Etape 4 : reproduire avec valgrind
- Etape 5 : verifier les bibliotheques partagees
- Cas particulier : segfault dans un conteneur Docker
- Repères pour aller plus loin
Comprendre ce que la segfault mesure
Chaque processus a un espace d’adresses virtuelles divise en zones : le code (text), les donnees initialisees (data), le tas (heap), la pile (stack) et les bibliotheques partagees. Quand un programme ecrit dans la zone code ou lit dans une adresse qui n’est pas mappee, le noyau declenche une segfault. Les causes courantes sont :
- Pointeur nul ou invalide : le programme dereference un pointeur qui vaut 0 ou une adresse arbitraire
- Depassement de tableau : l’ecriture depasse la fin d’un tableau alloue sur la pile
- Double free : le programme libere deux fois la meme zone memoire
- Buffer overflow : l’ecriture depasse un buffer alloue sur le tas
- Version incompatibilite : une bibliotheque partagee attend une structure que le programme ne fournit pas
Etape 1 : activer les core dumps
Par defaut, les core dumps sont desactives sur la plupart des distributions. Pour les activer temporairement :
ulimit -c unlimited
ulimit -a | grep core
La deuxieme commande doit afficher core file size (blocks, -c) unlimited. Ensuite, relancez le programme qui plante. Un fichier core ou core.PID apparait dans le repertoire courant ou dans /var/crash/ selon la configuration. Pour un core dump permanent, configurez core_pattern :
echo '/var/crash/core.%e.%p' | sudo tee /proc/sys/kernel/core_pattern
Le pattern %e donne le nom du programme, %p le PID. Le wiki Debian « Core dump » documente les options de core_pattern.
Etape 2 : lire le backtrace avec gdb
GDB (GNU Debugger) lit le core dump et affiche la pile d’appels au moment du crash :
gdb /usr/bin/monprogramme core
(gdb) bt
(gdb) bt full
(gdb) info registers
La commande bt (backtrace) affiche la pile d’appels : la premiere ligne indique la fonction qui a plante, les lignes suivantes montrent qui l’a appelee. bt full ajoute les valeurs des variables locales. info registers affiche les registres CPU au moment du crash, utile pour identifier un depassement de tampon. Si gdb n’est pas installe : sudo apt install gdb.
Etape 3 : identifier la cause la plus probable
Le backtrace donne l’indice principal :
| Symbole dans bt | Cause probable | Correction |
|---|---|---|
__memcpy ou __strcpy | Buffer overflow / depassement de tableau | Verifier la taille du buffer et les bornes d’ecriture |
free | Double free ou free sur pointeur invalide | Ajouter valgrind pour detecter la fuite |
malloc | Heap corruption prealable | Relancer avec valgrind --tool=memcheck |
sigaction ou __restore_rt | Signal non gere (SIGSEGV recurse) | Ajouter un gestionnaire de signal ou corriger le code |
Etape 4 : reproduire avec valgrind
Valgrind simule l’espace memoire et detecte les erreurs avant qu’elles ne causent une segfault :
valgrind --tool=memcheck --leak-check=full /usr/bin/monprogramme
Valgrind ralentit le programme (x5 a x50), mais il affiche l’adresse exacte de l’erreur, la ligne de code responsable et le type d’erreur (use-after-free, invalid write, uninitialised value). C’est l’outil le plus fiable pour diagnostiquer une segfault dont le backtrace ne suffit pas a expliquer la cause.
Etape 5 : verifier les bibliotheques partagees
Une segfault au demarrage (avant que le programme ne fasse quoi que ce soit) indique souvent une incompatibilite de bibliotheque :
ldd /usr/bin/monprogramme
ldd /usr/bin/monprogramme | grep "not found"
Si une bibliotheque est not found ou a une version incompatible, le programme plante au chargement. La correction est d’installer la bonne version ou de recompiler le programme contre les bibliotheques disponibles.
Cas particulier : segfault dans un conteneur Docker
Dans un conteneur, les core dumps sont souvent desactives par defaut. Ajoutez --cap-add=SYS_PTRACE au docker run pour permettre le diagnostic, ou utilisez --security-opt seccomp=unconfined si le programme a besoin d’acces systeme etendu. Le core dump se lit de la meme maniere avec gdb, mais le chemin du programme est celui du conteneur, pas celui de l’hote.
Repères pour aller plus loin
- Services et journaux systemd : quand un service plante et redemarre
- Too many open files : quand la limite de descripteurs cause un crash
- Diagnostiquer une connexion : quand le probleme est reseau, pas memoire
- Fail2ban : proteger SSH sans bloquer les connexions legitimes