Menu
Coddy logo textTech

Qu'est-ce qu'une segmentation fault (erreur de segmentation) ?

Une segmentation fault, ou segfault (erreur de segmentation), est un plantage qui se produit quand un programme essaie de lire ou d'écrire une zone mémoire à laquelle il n'a pas le droit d'accéder, comme l'adresse 0 via un pointeur nul. Le système d'exploitation arrête le programme avec le signal SIGSEGV.

Par Kevin Spektor, Cofondateur et CTO

Mis à jour le 24 septembre 2026

Un programme C affiche sa première ligne, puis s'arrête avec un message que personne n'a écrit :

#include <stdio.h>

int main(void) {
    int *score = NULL;

    printf("About to read the score\n");
    printf("Score: %d\n", *score);
    return 0;
}
About to read the score
bash: line 1: 64030 Segmentation fault: 11  ./seg

Cette sortie vient de bash sur macOS, où 64030 est l'identifiant du processus et 11 le numéro du signal. Sous Linux, le même plantage s'affiche généralement sous la forme Segmentation fault (core dumped). Dans les deux cas, le programme n'a jamais affiché le score. score contient l'adresse 0, et *score demande au processeur de lire la mémoire à cette adresse, ce qu'aucun programme n'a le droit de faire.

Comment se produit une segmentation fault

Chaque programme tourne dans son propre espace d'adressage virtuel, une immense plage d'adresses que le système d'exploitation remplit morceau par morceau. Il y projette le code du programme, ses variables globales, sa pile et son tas, par blocs appelés pages (4 Ko sur la plupart des systèmes Linux x86, 16 Ko sur les Mac à puce Apple). La plupart des adresses restent non projetées, et l'adresse 0 en fait toujours partie, pour que les bugs de pointeur nul soient détectés.

  1. Le programme exécute une instruction qui lit ou écrit une adresse. Ici, c'est la lecture de *score, l'adresse 0.
  2. L'unité de gestion mémoire du processeur cherche l'adresse dans la table des pages. La page n'est pas projetée, ou le programme essaie d'écrire dans une page en lecture seule.
  3. Le processeur arrête l'instruction et passe la main au noyau avec un défaut de page.
  4. Le noyau vérifie si l'accès pourrait être légitime, par exemple une pile qui doit grandir. Ce n'est pas le cas, donc le noyau envoie au processus le signal 11, SIGSEGV.
  5. L'action par défaut pour SIGSEGV est de terminer le processus et, quand le système le permet, d'enregistrer un core dump. Le shell affiche alors le message et fixe le code de sortie à 139, soit 128 plus le numéro du signal.

Une segmentation fault n'est donc pas signalée par le compilateur, et ce n'est pas une exception levée par le langage. C'est le matériel et le noyau qui protègent la mémoire, ce qui en fait une erreur d'exécution de la forme la plus brutale. Windows traite le même événement comme une violation d'accès, avec le code d'exception 0xC0000005.

Causes courantes des segmentation faults

Le C et le C++ laissent un programme calculer n'importe quelle adresse et l'utiliser, donc les causes se ramènent toutes à l'utilisation d'une adresse invalide.

  • Déréférencer un pointeur nul. int *p = NULL; *p = 5; Une fonction qui renvoie NULL en cas d'échec, comme malloc ou fopen, mène ici quand son résultat n'est pas vérifié.
  • Un index loin après la fin d'un tableau. Le C ne vérifie pas les bornes, donc arr[1000000] est simplement une adresse située un million d'éléments plus loin.
  • Utiliser la mémoire après free. Le pointeur contient toujours l'ancienne adresse, mais la mémoire ne t'appartient plus.
  • Un pointeur non initialisé. int *p; *p = 5; écrit à travers la valeur aléatoire que p se trouve contenir.
  • Un dépassement de pile. Une fonction récursive sans cas d'arrêt continue d'ajouter des cadres de pile jusqu'à dépasser la fin de la pile. L'exemple ci-dessous a planté sur macOS avec Segmentation fault: 11 et le code de sortie 139.
  • Écrire dans une chaîne littérale. char *name = "coddy"; name[0] = 'C'; essaie de modifier de la mémoire en lecture seule. Sous Linux, c'est une segfault. Sur macOS, le même programme s'est arrêté avec Bus error: 10, un signal voisin.
#include <stdio.h>

int depth(int n) {
    return depth(n + 1) + 1;   /* never stops calling itself */
}

int main(void) {
    printf("%d\n", depth(0));
    return 0;
}

Une petite faute ne provoque souvent aucun plantage, ce qui la rend plus dangereuse. Cette boucle lit un élément après la fin d'un tableau de trois éléments :

#include <stdio.h>

int main(void) {
    int scores[3] = {72, 88, 95};
    int total = 0;

    for (int i = 0; i <= 3; i++) {   /* <= reads scores[3] */
        total += scores[i];
    }
    printf("Total: %d\n", total);
    return 0;
}

Compilé avec Clang sur un Mac, il a affiché Total: 256. Le bon total est 255. scores[3] correspondait aux 4 octets suivants de la pile, qui appartenaient au programme, donc aucune faute ne s'est produite et la valeur aléatoire a été ajoutée en silence. Le système d'exploitation n'arrête que les accès à de la mémoire que le programme ne possède pas du tout.

La correction de ces deux fautes est la même habitude : sache combien il y a d'éléments, et vérifie un pointeur avant de le suivre.

Best: 95
No scores, nothing to read

Ce que signifie « core dumped »

Un core dump est un fichier qui contient une copie de la mémoire du programme au moment du plantage. Un débogueur peut l'ouvrir plus tard et montrer exactement où en était le programme et ce que contenaient ses variables : gdb ./app core. Sur de nombreuses distributions Linux, systemd-coredump collecte ces fichiers, et coredumpctl list les affiche. Quand les core dumps sont désactivés, par exemple avec ulimit -c 0, le message est simplement Segmentation fault, sans les mots entre parenthèses.

Comment trouver la ligne qui a planté

La ligne où le programme plante n'est souvent pas celle qui contient le bug. Un pointeur peut devenir invalide dans une fonction et être utilisé dans une autre bien plus tard. Ces outils montrent les deux.

Un débogueur. Compile avec les informations de débogage et lance le programme dans le débogueur. Quand il s'arrête, bt (backtrace) affiche la chaîne des appels de fonctions avec les noms de fichiers et les numéros de ligne. Sous Linux, le débogueur est généralement gdb ; sur macOS, c'est lldb, où bt fonctionne de la même façon.

gcc -g app.c -o app
gdb ./app
(gdb) run
(gdb) bt

AddressSanitizer. Compile avec -fsanitize=address (GCC et Clang le prennent tous deux en charge) et lance le programme normalement. Au lieu d'une segfault brute, il affiche un rapport qui nomme le type de faute, comme heap-use-after-free ou stack-buffer-overflow, avec la ligne qui a fait l'accès et la ligne qui a alloué la mémoire. Il détecte aussi la lecture silencieuse d'un élément après la fin vue plus haut, qui ne plante jamais d'elle-même.

Valgrind. Sous Linux, valgrind ./app exécute un programme non modifié et signale chaque lecture ou écriture invalide, comme Invalid read of size 4.

Les segmentation faults dans d'autres langages

Python, Java et JavaScript vérifient chaque index et chaque référence avant de les utiliser, donc les mêmes fautes deviennent des exceptions avec des messages clairs : IndexError ou AttributeError en Python, ArrayIndexOutOfBoundsException ou NullPointerException en Java, TypeError en JavaScript. Celles-ci peuvent être attrapées avec la gestion des exceptions. Une segfault ne peut pas être gérée ainsi : c'est un signal, et un bloc catch C++ ne la voit pas.

Les programmes Python peuvent quand même planter en segfault quand du code C échoue en dessous d'eux. Cette ligne demande à ctypes de lire l'adresse 0 :

import ctypes
ctypes.string_at(0)

Lancé avec python3 -X faulthandler, Python 3.12 a affiché Fatal Python error: Segmentation fault, suivi des lignes Python qui s'exécutaient. Le même plantage se produit quand une extension C ou une bibliothèque native a un bug mémoire. Rust adopte une autre approche : son compilateur rejette la plupart du code qui pourrait accéder à de la mémoire invalide avant même que le programme soit construit.

Pour aller plus loin

Le guide C sur les segmentation faults passe en revue chaque cause avec un programme minimal et sa correction. Pour éviter ces fautes dès le départ, lis les pages sur les pointeurs, les pointeurs nuls et la pile et le tas, puis pratique-les dans le cours C. Pour voir comment les erreurs sont signalées dans les langages qui vérifient la mémoire pour toi, consulte la page erreur d'exécution.

Questions fréquentes

Comment corriger une segmentation fault ?
Trouve d'abord la ligne : compile avec -g et lance le programme dans gdb ou lldb, puis tape bt après le plantage, ou compile avec -fsanitize=address pour obtenir un rapport détaillé. Corrige ensuite le pointeur ou l'index qu'utilise cette ligne : vérifie les pointeurs contre NULL, garde les index de tableau sous la longueur, n'utilise plus la mémoire après free, et assure-toi que la récursion se termine.
Une segmentation fault est-elle une fuite de mémoire ?
Non, ce sont des problèmes opposés. Une fuite de mémoire, c'est de la mémoire que le programme a allouée et jamais libérée : il continue de tourner en utilisant de plus en plus de mémoire. Une segmentation fault est un accès à de la mémoire que le programme ne possède pas, et le programme est arrêté immédiatement. Les fautes avec free, comme utiliser un pointeur après l'avoir libéré, peuvent causer des segfaults, alors qu'oublier free cause des fuites.
Pourquoi parle-t-on de segmentation fault ?
Le nom vient de la segmentation mémoire, une conception ancienne dans laquelle la mémoire d'un programme était divisée en segments aux limites fixes, et toucher une adresse hors de son segment était une faute. Les systèmes modernes gèrent la mémoire par pages, mais le nom est resté, tout comme le nom du signal SIGSEGV. Windows appelle le même événement une violation d'accès.
Python peut-il provoquer une segmentation fault ?
Du code Python ordinaire n'en provoque pas, car Python vérifie chaque index et chaque référence et lève une exception à la place. Un programme Python peut quand même planter en segfault à l'intérieur de code C : un module d'extension C, une bibliothèque comme un framework de machine learning, ou ctypes. Lancer python -X faulthandler script.py affiche les lignes Python qui s'exécutaient au moment du plantage.
Que signifie le code de sortie 139 ?
Le code de sortie 139 signifie que le processus a été tué par le signal 11, c'est-à-dire SIGSEGV, une segmentation fault. Les shells signalent une mort par signal comme 128 plus le numéro du signal, et 128 + 11 = 139. Dans Docker et Kubernetes, un conteneur qui se termine avec 139 a vu son processus principal planter en segfault.
Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER