web-dev-qa-db-fra.com

Déterminez la ligne de code qui cause une erreur de segmentation?

Comment pouvons-nous déterminer où se trouve l'erreur dans notre code qui cause un erreur de segmentation ?

Après avoir écrit du code, afin de déterminer où j’ai un problème de segmentation, mon compilateur (gcc) peut-il me montrer l’emplacement du défaut dans mon programme?

131
user319824

GCC ne peut pas faire cela, mais GDB (un débogueur ) peut le faire. Compilez votre programme en utilisant le -g _ switch, comme ceci:

gcc program.c -g

Ensuite, utilisez gdb:

$ gdb ./a.out
(gdb) run
<segfault happens here>
(gdb) backtrace
<offending code is shown here>

Here est un bon tutoriel pour vous familiariser avec GDB.

180
nc3b

Vous pouvez également essayer Valgrind: si vous installez Valgrind et exécutez valgrind --leak-check = full, il exécutera votre programme et affichera les traces de pile de tous les segfaults, ainsi que des lectures ou écritures de mémoire non valides et des fuites de mémoire. . C'est vraiment très utile.

37
jwkpiano1

Vous pouvez également utiliser un core dump, puis l'examiner avec gdb. Pour obtenir des informations utiles, vous devez également compiler avec le -g drapeau.

Chaque fois que vous recevez le message:

 Segmentation fault (core dumped)

un fichier de base est écrit dans votre répertoire actuel. Et vous pouvez l'examiner avec la commande

 gdb your_program core_file

Le fichier contient l'état de la mémoire lorsque le programme est tombé en panne. Un vidage 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 principal à zéro. Vous pouvez le définir en illimité avec:

ulimit -c unlimited

Attention cependant! ces dépotoirs peuvent devenir énormes.

17
Lucas

Il existe un certain nombre d'outils disponibles qui aident à déboguer les erreurs de segmentation et j'aimerais ajouter mon outil préféré à la liste: Désinfecteurs d'adresses (souvent abrégé ASAN) .

Les compilateurs modernes¹ sont livrés avec le pratique -fsanitize=address drapeau, ajoutant du temps de compilation et une surcharge de temps d’exécution qui permet de vérifier davantage les erreurs.

Selon la documentation , ces vérifications incluent la capture des erreurs 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:

int main() {
  volatile int *ptr = (int*)0;
  *ptr = 0;
}
$ gcc -g -fsanitize=address main.c
$ ./a.out
AddressSanitizer:DEADLYSIGNAL
=================================================================
==4848==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5654348db1a0 bp 0x7ffc05e39240 sp 0x7ffc05e39230 T0)
==4848==The signal is caused by a WRITE memory access.
==4848==Hint: address points to the zero page.
    #0 0x5654348db19f in main /tmp/tmp.s3gwjqb8zT/main.c:3
    #1 0x7f0e5a052b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)
    #2 0x5654348db099 in _start (/tmp/tmp.s3gwjqb8zT/a.out+0x1099)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /tmp/tmp.s3gwjqb8zT/main.c:3 in main
==4848==ABORTING

La sortie est légèrement plus compliquée que ce que gdb produirait, mais il existe des avantages:

  • Il n'est pas nécessaire de reproduire le problème pour recevoir une trace de pile. Activer simplement le drapeau pendant le développement suffit.

  • Les ASAN attrapent bien plus que des erreurs de segmentation. De nombreux accès hors limites seront capturés même si cette zone de mémoire était accessible au processus.


¹ C'est-à-dire Clang 3.1 + et GCC 4.8 + .

4
asynts

La réponse de Lucas à propos des dépotoirs est bonne. Dans mon .cshrc j'ai:

alias core 'ls -lt core; echo where | gdb -core=core -silent; echo "\n"'

pour afficher la trace en entrant 'core'. Et le timbre à date, pour m'assurer que je regarde le bon fichier :(.

Ajouté: S'il y a un bogue de corruption de pile , la trace de retour appliquée au dump principal est souvent fouillie. Dans ce cas, l'exécution du programme dans gdb peut donner de meilleurs résultats, conformément à la réponse acceptée (en supposant que le défaut soit facilement reproductible). Et aussi méfiez-vous des processus multiples déchargeant le noyau simultanément; Certains OS ajoutent le PID au nom du fichier core.

2
Joseph Quinsey