Comment déterminer où se trouve l'erreur dans le code qui provoque une erreur de segmentation ?
Mon compilateur ( gcc
) peut-il afficher l'emplacement de l'erreur dans le programme?
c++
c
debugging
segmentation-fault
Trilarion
la source
la source
Réponses:
GCC ne peut pas faire cela mais GDB (un débogueur ) le peut. Compilez votre programme en utilisant le
-g
commutateur, comme ceci:Ensuite, utilisez gdb:
Voici un joli tutoriel pour vous familiariser avec GDB.
L'endroit où se produit l'erreur de segmentation n'est généralement qu'un indice quant à l'endroit où «l'erreur qui la cause» se trouve dans le code. L'emplacement donné n'est pas nécessairement celui où réside le problème.
la source
bt
comme raccourci pourbacktrace
.En outre, vous pouvez
valgrind
essayer: si vous installezvalgrind
et exécutezpuis il exécutera votre programme et affichera les traces de pile pour tous les segfaults, ainsi que toutes les lectures ou écritures de mémoire invalides et les fuites de mémoire. C'est vraiment très utile.
la source
--leak-check=full
n'aidera pas à déboguer les segfaults. Il n'est utile que pour déboguer les fuites de mémoire.Vous pouvez également utiliser un vidage de mémoire, puis l'examiner avec gdb. Pour obtenir des informations utiles, vous devez également compiler avec l'
-g
indicateur.Chaque fois que vous recevez le message:
un fichier core est écrit dans votre répertoire actuel. Et vous pouvez l'examiner avec la commande
Le fichier contient l'état de la mémoire lorsque le programme s'est écrasé. Un vidage de mémoire peut être utile lors du déploiement de votre logiciel.
Assurez-vous que votre système ne définit pas la taille du fichier de vidage de mémoire sur zéro. Vous pouvez le définir sur illimité avec:
ulimit -c unlimited
Attention cependant! que les décharges de base peuvent devenir énormes.
la source
Il existe un certain nombre d'outils disponibles qui aident à déboguer les erreurs de segmentation et je voudrais ajouter mon outil préféré à la liste: Address Sanitizers (souvent abrégé ASAN) .
Les compilateurs modernes sont livrés avec l'
-fsanitize=address
indicateur pratique , ajoutant un peu de temps de compilation et de temps d'exécution, ce qui fait plus de vérification des erreurs.Selon la documentation, ces contrôles incluent la détection des défauts de segmentation par défaut. L'avantage ici est que vous obtenez une trace de pile similaire à la sortie de gdb, mais sans exécuter le programme dans un débogueur. Un exemple:
La sortie est légèrement plus compliquée que ce que gdb produirait mais il y a des avantages:
Il n'est pas nécessaire de reproduire le problème pour recevoir une trace de pile. Il suffit d'activer le drapeau pendant le développement.
Les ASAN détectent bien plus que de simples défauts de segmentation. De nombreux accès hors limites seront interceptés même si cette zone de mémoire était accessible au processus.
¹ C'est Clang 3.1+ et GCC 4.8+ .
la source
La réponse de Lucas sur les vidages de mémoire est bonne. Dans mon .cshrc j'ai:
pour afficher la trace arrière en saisissant «core». Et le cachet de la date, pour m'assurer que je regarde le bon fichier :(.
Ajouté : S'il y a un bogue de corruption de pile , alors la trace appliquée au vidage de mémoire est souvent des ordures. Dans ce cas, l'exécution du programme dans gdb peut donner de meilleurs résultats, selon la réponse acceptée (en supposant que l'erreur est facilement reproductible). Et méfiez-vous également des processus multiples vidant le noyau simultanément; certains OS ajoutent le PID au nom du fichier core.
la source
ulimit -c unlimited
d'activer les vidages de mémoire en premier lieu.Toutes les réponses ci-dessus sont correctes et recommandées; cette réponse n'est destinée qu'en dernier recours si aucune des approches susmentionnées ne peut être utilisée.
Si tout le reste échoue, vous pouvez toujours recompiler votre programme avec diverses instructions de débogage temporaires (par exemple
fprintf(stderr, "CHECKPOINT REACHED @ %s:%i\n", __FILE__, __LINE__);
) saupoudrées dans ce que vous pensez être les parties pertinentes de votre code. Ensuite, exécutez le programme et observez la dernière impression de débogage imprimée juste avant le crash - vous savez que votre programme est arrivé jusque-là, donc le crash a dû se produire après ce point. Ajoutez ou supprimez des impressions de débogage, recompilez et réexécutez le test, jusqu'à ce que vous l'ayez réduit à une seule ligne de code. À ce stade, vous pouvez corriger le bogue et supprimer toutes les impressions de débogage temporaires.C'est assez fastidieux, mais cela a l'avantage de fonctionner à peu près n'importe où - les seules fois où ce n'est peut-être pas si vous n'avez pas accès à stdout ou stderr pour une raison quelconque, ou si le bogue que vous essayez de corriger est une course -condition dont le comportement change lorsque le timing du programme change (puisque les impressions de débogage ralentiront le programme et changeront son timing)
la source