web-dev-qa-db-fra.com

Correction des erreurs de segmentation en C ++

J'écris un programme C++ multiplateforme pour Windows et Unix. Côté Windows, le code se compilera et ne s'exécutera pas de problème. Du côté Unix, il se compile cependant quand j'essaye de l'exécuter, j'obtiens un défaut de segmentation. Mon intuition initiale est qu'il y a un problème avec les pointeurs.

Quelles sont les bonnes méthodologies pour trouver et corriger les erreurs de segmentation?

66
Elpezmuerto
  1. Compilez votre application avec -g, vous aurez alors des symboles de débogage dans le fichier binaire.

  2. Utilisez gdb pour ouvrir la console gdb.

  3. Utilisez file et passez-lui le fichier binaire de votre application dans la console.

  4. Utilisez run et passez tous les arguments dont votre application a besoin pour démarrer.

  5. Faites quelque chose pour provoquer un défaut de segmentation.

  6. Tapez bt dans la console gdb pour obtenir une trace de pile de Erreur de segmentation.

101
Svisstack

Parfois, le crash lui-même n'est pas la véritable cause du problème - peut-être que la mémoire a été brisée à un moment antérieur, mais il a fallu un certain temps pour que la corruption se manifeste. Découvrez valgrind , qui a beaucoup de vérifications pour les problèmes de pointeur (y compris la vérification des limites du tableau). Il vous dira où le problème commence , pas seulement la ligne où le crash se produit.

29
paleozogt

Avant que le problème ne survienne, essayez de l'éviter autant que possible:

  • Compilez et exécutez votre code aussi souvent que possible. Il sera plus facile de localiser la pièce défectueuse.
  • Essayez d'encapsuler des routines de bas niveau/sujettes aux erreurs afin que vous ayez rarement à travailler directement avec la mémoire (faites attention à la modélisation de votre programme)
  • Maintenir une suite de tests. Avoir un aperçu de ce qui fonctionne actuellement, de ce qui ne fonctionne plus, etc., vous aidera à déterminer où est le problème ( Boost test est une solution possible, je ne l'utilise pas moi-même mais le la documentation peut aider à comprendre quel type d'informations doit être affiché).

Utilisez les outils appropriés pour le débogage. Sous Unix:

  • GDB peut vous dire où vous programmez le crash et vous permettra de voir dans quel contexte.
  • Valgrind vous aidera à détecter de nombreuses erreurs liées à la mémoire.
  • Avec GCC, vous pouvez également utiliser bavette Avec GCC et Clang, vous pouvez utiliser Address/Memory Sanitizer . Il peut détecter certaines erreurs que Valgrind ne détecte pas et la perte de performances est plus légère.

Enfin, je recommanderais les choses habituelles. Plus votre programme est lisible, maintenable, clair et net, plus il sera facile à déboguer.

16
log0

Sous Unix, vous pouvez utiliser valgrind pour rechercher des problèmes. C'est gratuit et puissant. Si vous préférez le faire vous-même, vous pouvez surcharger les nouveaux opérateurs et supprimer des opérateurs pour définir une configuration dans laquelle vous avez 1 octet avec 0xDEADBEEF avant et après chaque nouvel objet. Suivez ensuite ce qui se passe à chaque itération. Cela peut ne pas tout attraper (vous n'êtes même pas sûr de toucher à ces octets) mais cela a fonctionné pour moi dans le passé sur une plate-forme Windows.

3
wheaties

Oui, il y a un problème avec les pointeurs. Il est très probable que vous en utilisiez un qui n'est pas correctement initialisé, mais il est également possible que vous gâchiez votre gestion de la mémoire avec des doubles libérations ou autres.

Pour éviter les pointeurs non initialisés en tant que variables locales, essayez de les déclarer le plus tard possible, de préférence (et ce n'est pas toujours possible) lorsqu'ils peuvent être initialisés avec une valeur significative. Convainquez-vous qu'ils auront une valeur avant d'être utilisés, en examinant le code. Si vous avez des difficultés avec cela, initialisez-les à une constante de pointeur nul (généralement écrit comme NULL ou 0) Et vérifiez-les.

Pour éviter les pointeurs non initialisés en tant que valeurs de membre, assurez-vous qu'ils sont correctement initialisés dans le constructeur et traités correctement dans les constructeurs de copie et les opérateurs d'affectation. Ne comptez pas sur une fonction init pour la gestion de la mémoire, bien que vous puissiez le faire pour d'autres initialisations.

Si votre classe n'a pas besoin de constructeurs de copie ou d'opérateurs d'affectation, vous pouvez les déclarer en tant que fonctions membres privées et ne jamais les définir. Cela provoquera une erreur de compilation si elles sont utilisées explicitement ou implicitement.

Utilisez des pointeurs intelligents, le cas échéant. Le gros avantage ici est que, si vous vous en tenez à eux et les utilisez de manière cohérente, vous pouvez complètement éviter d'écrire delete et rien ne sera double-supprimé.

Utilisez des chaînes C++ et des classes de conteneur autant que possible, au lieu de chaînes et de tableaux de style C. Pensez à utiliser .at(i) plutôt que [i], Car cela forcera la vérification des limites. Vérifiez si votre compilateur ou votre bibliothèque peut être configuré pour vérifier les limites sur [i], Au moins en mode débogage. Les erreurs de segmentation peuvent être causées par des dépassements de tampon qui écrivent des ordures sur des pointeurs parfaitement bons.

Faire ces choses réduira considérablement la probabilité d'erreurs de segmentation et d'autres problèmes de mémoire. Ils échoueront sans doute à tout réparer, et c'est pourquoi vous devriez utiliser valgrind de temps en temps lorsque vous n'avez pas de problèmes, et valgrind et gdb lorsque vous en avez.

2
David Thornley

Je ne connais aucune méthodologie à utiliser pour réparer des choses comme ça. Je ne pense pas qu'il serait possible d'en trouver un non plus car le problème est que le comportement de votre programme n'est pas défini (je ne connais aucun cas où SEGFAULT n'a pas été causé par une sorte d'UB) .

Il existe toutes sortes de "méthodologies" pour éviter le problème avant qu'il ne survienne. Un RAII important.

En plus de cela, vous n'avez qu'à y jeter vos meilleures énergies psychiques.

0
Edward Strange