FAQ CConsultez toutes les FAQ

Nombre d'auteurs : 34, nombre de questions : 194, dernière mise à jour : 18 février 2018  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de www.developpez.com et de l'expérience personnelle des auteurs.

Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci .

Sur ce, je vous souhaite une bonne lecture.


SommairePointeurs, tableaux et chaînes de caractèresLes erreurs de segmentation (9)
précédent sommaire suivant
 

Il s'agit d'une erreur très courante qui se produit lorsque votre programme essaie de lire ou d'écrire dans une zone mémoire qui ne lui a pas été attribuée par le système d'exploitation.

Mis à jour le 27 décembre 2017 Bktero LittleWhite Obsidian

Par défaut, un programme en langage machine a accès sans restriction à la totalité du plan mémoire de la machine. C'est de cette façon que fonctionnaient les anciennes architectures telles que les 8 bits, la plupart des microcontrôleurs et les ordinateurs compatibles PC en mode réel (notamment sous D.O.S.). Néanmoins, si ce programme s'avère défectueux et se met à écrire de manière incontrôlée dans la mémoire vive, il peut écraser ce qui s'y trouve : ses propres données, les données sur le disque ou encore le système d'exploitation.

Puisqu'un programme en langage machine est, par définition, exécuté directement par le microprocesseur, sans couche intermédiaire, il n'est pas possible de mettre en place un contrôle logiciel pour empêcher un tel programme de mal se comporter. Pour remédier à cela, les architectures modernes embarquent un dispositif électronique placé soit directement au sein du microprocesseur, soit dans l'unité de gestion de la mémoire permettant de vérifier si les adresses mémoire présentées sur le bus sont comprises dans des limites fixées à l'avance. Si ce n'est pas le cas, une « exception » est déclenchée. Celle-ci provoque un renvoi immédiat vers un sous-programme du système d'exploitation qui, en l'absence d'instructions spécifiques, met fin au programme fautif.

Notez également que le système d'exploitation alloue une plage de travail au processus qui l'organise ensuite comme bon lui semble. Cela signifie qu'il mettra fin à un programme essayant d'écrire sur les autres processus, mais qu'il le laissera faire s'il écrase ses propres données. Ainsi, un logiciel qui ne plante pas n'est pas forcément correct pour autant. Des données invalides peuvent apparaître après coup, et un programme réputé fonctionnel peut devenir défectueux sans explication lorsqu'il est compilé sur une autre architecture.

Mis à jour le 27 décembre 2017 Bktero LittleWhite Obsidian

En langage C, une erreur de segmentation est provoquée dans la grande majorité des cas par un pointeur invalide. Elle peut également être le fait d'un dépassement de tableau ou d'un débordement de pile.

Mis à jour le 27 décembre 2017 Bktero LittleWhite Obsidian

Lorsque vous êtes confrontés à une erreur de segmentation, lancez votre programme dans un débogueur. Ce dernier s'arrêtera automatiquement à la ligne provoquant le crash. Examinez la ligne incriminée et voyez si elle utilise un pointeur (où l'adresse d'une variable obtenue avec l'opérateur « & », par exemple). Il est très probable que la valeur de celui-ci soit incorrecte, obsolète, ou qu'elle référence un objet trop petit pour recevoir ce qu'on veut lui affecter. Grâce au débogueur, vous pouvez rapidement déterminer l'origine du crash, en affichant la valeur du pointeur ou de l'index du tableau incriminé à la ligne où le débogueur s'est arrêté.

Mis à jour le 27 décembre 2017 Bktero LittleWhite Obsidian

Le débogueur ne vous aidera pas toujours, notamment si le l'erreur de segmentation est provoquée par une corruption de la mémoire ayant eu lieu plus tôt dans l'exécution du programme.

Pour cela, il existe un autre type de programmes, les analyseurs de mémoire, qui eux vont vous permettre de détecter les erreurs liées à la mémoire (même si cela ne provoque pas de plantage) ainsi que des fuites de mémoire.

Sous Linux, vous avez valgrind. Sous Windows, l'équivalent est Dr Memory. Vous pouvez aussi utiliser MTuner.

Mis à jour le 27 décembre 2017 Bktero LittleWhite Obsidian

Le code suivant provoque une erreur de segmentation :

Code C : Sélectionner tout
1
2
3
char * ptr; 
  
strcpy (ptr,"Test");
ptr est un pointeur vers un caractère (ou une suite de caractères consécutifs), mais sa valeur n'a pas été définie et est donc indéterminée à ce stade. Aucun espace n'a encore été alloué pour recevoir la chaîne copiée par strcpy().

Mis à jour le 27 décembre 2017 Bktero LittleWhite Obsidian

Le code suivant provoque une erreur de segmentation :

Code C : Sélectionner tout
1
2
3
4
5
6
int buffer[256], i; 
  
for (i=0 ; i<512 ; i++)  
{ 
    buffer[i] = 0; 
}
buffer est un tableau de 256 entiers, mais l'indice i court jusqu'à 512. En langage C, déclarer un tableau ne fait que réserver l'espace nécessaire pour ses éléments, auxquels on accède ensuite à l'aide d'un décalage (« offset ») par rapport au début du tableau. Indexer un élément de rang supérieur à la taille du tableau nous emmène au-delà de la mémoire effectivement réservée.

À noter que dans le cas de dépassements légers, de l'ordre d'un ou deux éléments seulement après la fin du tableau, il est probable que l'opération ne provoque pas d'erreur de segmentation, mais écrase les variables situées immédiatement après le tableau. Celles-ci voient alors leur valeur modifiée de façon indéfinie et sans avertissement, provoquant des bogues très difficiles à localiser.

Mis à jour le 27 décembre 2017 Bktero LittleWhite Obsidian

Le code suivant provoque une erreur de segmentation :

Code C : Sélectionner tout
1
2
3
4
void f() 
{ 
    f(); 
}
La fonction f() s'appelle elle-même, récursivement, mais aucune condition d'arrêt n'est définie. Les adresses de retour successives vont alors se cumuler dans la pile jusqu'à ce que son contenu dépasse l'espace qui lui est alloué. Lorsque la pile dispose de son propre segment, certains systèmes le détectent et affichent le message « stack overflow ». Sinon, le cas est traité comme une erreur de segmentation ordinaire.

Mis à jour le 27 décembre 2017 Bktero LittleWhite Obsidian

Code C : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h> 
  
int * calcul (int a, int b) 
{ 
    int resultat; 
  
    resultat = a + b; 
    return &resultat; 
} 
  
int main (void) 
{ 
    int * r; 
  
    r = calcul(1,2); 
    printf ("Résultat : %d\n", *r); 
    return 0; 
}
La fonction principale main() appelle la fonction calcul() qui, ici, effectue l'addition des nombres « 1 » et « 2 », sauvegarde le résultat dans la variable resultat et renvoie un pointeur vers cette variable. Malheureusement, il s'agit d'une variable locale à la fonction calcul() et dont l'espace est réservé dans la pile, ce qui signifie que lorsque ce pointeur parvient à main(), la variable en question n'existe déjà plus.

Généralement cet exemple produit un avertissement lors de la compilation.

Dans ce cas précis, il est probable que cet espace ne soit pas rendu immédiatement au système. Si la pile a été utilisée entre l'appel à calcul() et celui à printf() (par exemple à la suite d'une interruption), cette dernière renverra à l'écran un résultat indéfini. Dans le cas contraire, la mémoire sera restée dans l'état où on l'a laissée, renverra la bonne valeur, et donnera l'illusion que le programme fonctionne correctement alors qu'il n'en est rien.

Mis à jour le 27 décembre 2017 Bktero LittleWhite Obsidian

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2018 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
Contacter le responsable de la rubrique C