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?
Compilez votre application avec -g
, vous aurez alors des symboles de débogage dans le fichier binaire.
Utilisez gdb
pour ouvrir la console gdb.
Utilisez file
et passez-lui le fichier binaire de votre application dans la console.
Utilisez run
et passez tous les arguments dont votre application a besoin pour démarrer.
Faites quelque chose pour provoquer un défaut de segmentation.
Tapez bt
dans la console gdb
pour obtenir une trace de pile de Erreur de segmentation.
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.
Avant que le problème ne survienne, essayez de l'éviter autant que possible:
Utilisez les outils appropriés pour le débogage. Sous Unix:
Enfin, je recommanderais les choses habituelles. Plus votre programme est lisible, maintenable, clair et net, plus il sera facile à déboguer.
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.
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.
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.