CyberSDF

Reprenez la main sur votre numérique

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
  1. Comprendre ce que la segfault mesure
  2. Etape 1 : activer les core dumps
  3. Etape 2 : lire le backtrace avec gdb
  4. Etape 3 : identifier la cause la plus probable
  5. Etape 4 : reproduire avec valgrind
  6. Etape 5 : verifier les bibliotheques partagees
  7. Cas particulier : segfault dans un conteneur Docker
  8. 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 :

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 btCause probableCorrection
__memcpy ou __strcpyBuffer overflow / depassement de tableauVerifier la taille du buffer et les bornes d’ecriture
freeDouble free ou free sur pointeur invalideAjouter valgrind pour detecter la fuite
mallocHeap corruption prealableRelancer avec valgrind --tool=memcheck
sigaction ou __restore_rtSignal 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