Comment générer automatiquement une stacktrace lorsque mon programme gcc C ++ se bloque

Lorsque mon programme C ++ se bloque, j’aimerais qu’il génère automatiquement un stacktrace.

Mon programme est exécuté par de nombreux utilisateurs et fonctionne également sous Linux, Windows et Macintosh (toutes les versions sont compilées avec gcc ).

Je voudrais que mon programme soit capable de générer une trace de stack en cas de panne et que la prochaine fois que l’utilisateur l’exécute, il lui demandera s’il peut envoyer la trace de la stack pour que je puisse identifier le problème. Je peux gérer l’envoi de l’info mais je ne sais pas comment générer la chaîne de trace. Des idées?

    Pour Linux et Mac OS X, si vous utilisez gcc, ou tout autre compilateur utilisant glibc, vous pouvez utiliser les fonctions backtrace () dans execinfo.h pour imprimer un stacktrace et quitter normalement lorsque vous obtenez une erreur de segmentation. La documentation peut être trouvée dans le manuel de libc .

    Voici un exemple de programme qui installe un gestionnaire SIGSEGV et imprime un stacktrace pour stderr lorsqu’il se sépare. La fonction baz() provoque ici la erreur de segmentation qui déclenche le gestionnaire:

     #include  #include  #include  #include  #include  void handler(int sig) { void *array[10]; size_t size; // get void*'s for all ensortinges on the stack size = backtrace(array, 10); // print out all the frames to stderr fprintf(stderr, "Error: signal %d:\n", sig); backtrace_symbols_fd(array, size, STDERR_FILENO); exit(1); } void baz() { int *foo = (int*)-1; // make a bad pointer printf("%d\n", *foo); // causes segfault } void bar() { baz(); } void foo() { bar(); } int main(int argc, char **argv) { signal(SIGSEGV, handler); // install our handler foo(); // this will call foo, bar, and baz. baz segfaults. } 

    Comstackr avec -g -rdynamic vous -g -rdynamic obtenir des informations sur les symboles dans votre sortie, que glibc peut utiliser pour créer une belle trace de stack:

     $ gcc -g -rdynamic ./test.c -o test 

    En exécutant ceci vous obtenez cette sortie:

     $ ./test Error: signal 11: ./test(handler+0x19)[0x400911] /lib64/tls/libc.so.6[0x3a9b92e380] ./test(baz+0x14)[0x400962] ./test(bar+0xe)[0x400983] ./test(foo+0xe)[0x400993] ./test(main+0x28)[0x4009bd] /lib64/tls/libc.so.6(__libc_start_main+0xdb)[0x3a9b91c4bb] ./test[0x40086a] 

    Cela montre le module de chargement, le décalage et la fonction dont provient chaque image de la stack. Ici, vous pouvez voir le gestionnaire de signaux au-dessus de la stack, et les fonctions libc avant main en plus de main , foo , bar et baz .

    Linux

    Bien que l’utilisation des fonctions backtrace () dans execinfo.h pour imprimer un stacktrace et sortir gracieusement quand vous obtenez une erreur de segmentation a déjà été suggérée , je ne vois aucune mention des complexités nécessaires pour assurer que le backtrace résultant pointe vers l’emplacement réel de la faute (au moins pour certaines architectures – x86 et ARM).

    Les deux premières entrées de la chaîne de trames de la stack lorsque vous entrez dans le gestionnaire de signaux contiennent une adresse de retour dans le gestionnaire de signaux et une autre dans sigaction () dans la libc. Le frame de stack de la dernière fonction appelée avant que le signal (qui est l’emplacement de la panne) est perdu.

    Code

     #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifndef __USE_GNU #define __USE_GNU #endif #include  #include  #include  #include  #include  #include  #include  /* This structure mirrors the one found in /usr/include/asm/ucontext.h */ typedef struct _sig_ucontext { unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; struct sigcontext uc_mcontext; sigset_t uc_sigmask; } sig_ucontext_t; void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext) { void * array[50]; void * caller_address; char ** messages; int size, i; sig_ucontext_t * uc; uc = (sig_ucontext_t *)ucontext; /* Get the address at the time the signal was raised */ #if defined(__i386__) // gcc specific caller_address = (void *) uc->uc_mcontext.eip; // EIP: x86 specific #elif defined(__x86_64__) // gcc specific caller_address = (void *) uc->uc_mcontext.rip; // RIP: x86_64 specific #else #error Unsupported architecture. // TODO: Add support for other arch. #endif fprintf(stderr, "signal %d (%s), address is %p from %p\n", sig_num, strsignal(sig_num), info->si_addr, (void *)caller_address); size = backtrace(array, 50); /* overwrite sigaction with caller's address */ array[1] = caller_address; messages = backtrace_symbols(array, size); /* skip first stack frame (points here) */ for (i = 1; i < size && messages != NULL; ++i) { fprintf(stderr, "[bt]: (%d) %s\n", i, messages[i]); } free(messages); exit(EXIT_FAILURE); } int crash() { char * p = NULL; *p = 0; return 0; } int foo4() { crash(); return 0; } int foo3() { foo4(); return 0; } int foo2() { foo3(); return 0; } int foo1() { foo2(); return 0; } int main(int argc, char ** argv) { struct sigaction sigact; sigact.sa_sigaction = crit_err_hdlr; sigact.sa_flags = SA_RESTART | SA_SIGINFO; if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) != 0) { fprintf(stderr, "error setting signal handler for %d (%s)\n", SIGSEGV, strsignal(SIGSEGV)); exit(EXIT_FAILURE); } foo1(); exit(EXIT_SUCCESS); } 

    Sortie

     signal 11 (Segmentation fault), address is (nil) from 0x8c50 [bt]: (1) ./test(crash+0x24) [0x8c50] [bt]: (2) ./test(foo4+0x10) [0x8c70] [bt]: (3) ./test(foo3+0x10) [0x8c8c] [bt]: (4) ./test(foo2+0x10) [0x8ca8] [bt]: (5) ./test(foo1+0x10) [0x8cc4] [bt]: (6) ./test(main+0x74) [0x8d44] [bt]: (7) /lib/libc.so.6(__libc_start_main+0xa8) [0x40032e44] 

    Tous les risques d'appeler les fonctions backtrace () dans un gestionnaire de signal existent toujours et ne doivent pas être négligés, mais je trouve que les fonctionnalités que j'ai décrites ici sont très utiles pour le débogage des plantages.

    Il est important de noter que l'exemple que j'ai fourni est développé / testé sur Linux pour x86. Je l'ai également implémenté avec succès sur ARM en utilisant uc_mcontext.arm_pc au lieu de uc_mcontext.eip .

    Voici un lien vers l'article où j'ai appris les détails de cette implémentation: http://www.linuxjournal.com/article/6391

    C’est encore plus facile que “man backtrace”, il y a une bibliothèque peu documentée (spécifique à GNU) dissortingbuée avec glibc comme libSegFault.so, ce qui a été écrit par Ulrich Drepper pour supporter le programme catchsegv (voir “man catchsegv”).

    Cela nous donne 3 possibilités. Au lieu de lancer “program -o hai”:

    1. Exécuter dans catchsegv:

       $ catchsegv program -o hai 
    2. Lien avec libSegFault à l’exécution:

       $ LD_PRELOAD=/lib/libSegFault.so program -o hai 
    3. Lien avec libSegFault au moment de la compilation:

       $ gcc -g1 -lSegFault -o program program.cc $ program -o hai 

    Dans les 3 cas, vous obtiendrez des backtraces plus claires avec une optimisation moindre (gcc -O0 ou -O1) et des symboles de débogage (gcc -g). Sinon, vous risquez de vous retrouver avec une stack d’adresses mémoire.

    Vous pouvez également capturer plus de signaux pour les traces de stack avec quelque chose comme:

     $ export SEGFAULT_SIGNALS="all" # "all" signals $ export SEGFAULT_SIGNALS="bus abrt" # SIGBUS and SIGABRT 

    La sortie ressemblera à ceci (notez la trace en bas):

     *** Segmentation fault Register dump: EAX: 0000000c EBX: 00000080 ECX: 00000000 EDX: 0000000c ESI: bfdbf080 EDI: 080497e0 EBP: bfdbee38 ESP: bfdbee20 EIP: 0805640f EFLAGS: 00010282 CS: 0073 DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b Trap: 0000000e Error: 00000004 OldMask: 00000000 ESP/signal: bfdbee20 CR2: 00000024 FPUCW: ffff037f FPUSW: ffff0000 TAG: ffffffff IPOFF: 00000000 CSSEL: 0000 DATAOFF: 00000000 DATASEL: 0000 ST(0) 0000 0000000000000000 ST(1) 0000 0000000000000000 ST(2) 0000 0000000000000000 ST(3) 0000 0000000000000000 ST(4) 0000 0000000000000000 ST(5) 0000 0000000000000000 ST(6) 0000 0000000000000000 ST(7) 0000 0000000000000000 Backtrace: /lib/libSegFault.so[0xb7f9e100] ??:0(??)[0xb7fa3400] /usr/include/c++/4.3/bits/stl_queue.h:226(_ZNSt5queueISsSt5dequeISsSaISsEEE4pushERKSs)[0x805647a] /home/dbingham/src/middle-earth-mud/alpha6/src/engine/player.cpp:73(_ZN6Player5inputESs)[0x805377c] /home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:159(_ZN6Socket4ReadEv)[0x8050698] /home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:413(_ZN12ServerSocket4ReadEv)[0x80507ad] /home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:300(_ZN12ServerSocket4pollEv)[0x8050b44] /home/dbingham/src/middle-earth-mud/alpha6/src/engine/main.cpp:34(main)[0x8049a72] /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7d1b775] /build/buildd/glibc-2.9/csu/../sysdeps/i386/elf/start.S:122(_start)[0x8049801] 

    Si vous voulez connaître les détails, la meilleure source est malheureusement la source: Voir http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c et son répertoire parent http://sourceware.org/git/?p=glibc.git;a=tree;f=debug

    Même si une réponse correcte a été fournie qui décrit comment utiliser la fonction GNU libc backtrace() 1 et j’ai fourni ma propre réponse décrivant comment assurer une trace d’un gestionnaire de signaux vers l’emplacement réel de la panne 2 , Je ne vois aucune mention de démagnétisation des symboles C ++ issus du backtrace.

    Lors de l’obtention de backtraces à partir d’un programme C ++, la sortie peut être exécutée via c++filt 1 pour démêler les symboles ou en utilisant directement abi::__cxa_demangle 1 .

    • 1 Linux et OS X Notez que c++filt et __cxa_demangle sont spécifiques à GCC
    • 2 Linux

    L’exemple suivant de C ++ Linux utilise le même gestionnaire de signal que mon autre réponse et montre comment c++filt peut être utilisé pour démêler les symboles.

    Code :

     class foo { public: foo() { foo1(); } private: void foo1() { foo2(); } void foo2() { foo3(); } void foo3() { foo4(); } void foo4() { crash(); } void crash() { char * p = NULL; *p = 0; } }; int main(int argc, char ** argv) { // Setup signal handler for SIGSEGV ... foo * f = new foo(); return 0; } 

    Sortie ( ./test ):

     signal 11 (Segmentation fault), address is (nil) from 0x8048e07 [bt]: (1) ./test(crash__3foo+0x13) [0x8048e07] [bt]: (2) ./test(foo4__3foo+0x12) [0x8048dee] [bt]: (3) ./test(foo3__3foo+0x12) [0x8048dd6] [bt]: (4) ./test(foo2__3foo+0x12) [0x8048dbe] [bt]: (5) ./test(foo1__3foo+0x12) [0x8048da6] [bt]: (6) ./test(__3foo+0x12) [0x8048d8e] [bt]: (7) ./test(main+0xe0) [0x8048d18] [bt]: (8) ./test(__libc_start_main+0x95) [0x42017589] [bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981] 

    Sortie démanglée ( ./test 2>&1 | c++filt ):

     signal 11 (Segmentation fault), address is (nil) from 0x8048e07 [bt]: (1) ./test(foo::crash(void)+0x13) [0x8048e07] [bt]: (2) ./test(foo::foo4(void)+0x12) [0x8048dee] [bt]: (3) ./test(foo::foo3(void)+0x12) [0x8048dd6] [bt]: (4) ./test(foo::foo2(void)+0x12) [0x8048dbe] [bt]: (5) ./test(foo::foo1(void)+0x12) [0x8048da6] [bt]: (6) ./test(foo::foo(void)+0x12) [0x8048d8e] [bt]: (7) ./test(main+0xe0) [0x8048d18] [bt]: (8) ./test(__libc_start_main+0x95) [0x42017589] [bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981] 

    Ce qui suit se base sur le gestionnaire de signaux de ma réponse d’origine et peut remplacer le gestionnaire de signaux dans l’exemple ci-dessus pour démontrer comment abi::__cxa_demangle peut être utilisé pour démêler les symboles. Ce gestionnaire de signal produit la même sortie démanglée que l’exemple ci-dessus.

    Code :

     void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext) { sig_ucontext_t * uc = (sig_ucontext_t *)ucontext; void * caller_address = (void *) uc->uc_mcontext.eip; // x86 specific std::cerr < < "signal " << sig_num << " (" << strsignal(sig_num) << "), address is " << info->si_addr < < " from " << caller_address << std::endl << std::endl; void * array[50]; int size = backtrace(array, 50); array[1] = caller_address; char ** messages = backtrace_symbols(array, size); // skip first stack frame (points here) for (int i = 1; i < size && messages != NULL; ++i) { char *mangled_name = 0, *offset_begin = 0, *offset_end = 0; // find parantheses and +address offset surrounding mangled name for (char *p = messages[i]; *p; ++p) { if (*p == '(') { mangled_name = p; } else if (*p == '+') { offset_begin = p; } else if (*p == ')') { offset_end = p; break; } } // if the line could be processed, attempt to demangle the symbol if (mangled_name && offset_begin && offset_end && mangled_name < offset_begin) { *mangled_name++ = '\0'; *offset_begin++ = '\0'; *offset_end++ = '\0'; int status; char * real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status); // if demangling is successful, output the demangled function name if (status == 0) { std::cerr << "[bt]: (" << i << ") " << messages[i] << " : " << real_name << "+" << offset_begin << offset_end << std::endl; } // otherwise, output the mangled function name else { std::cerr << "[bt]: (" << i << ") " << messages[i] << " : " << mangled_name << "+" << offset_begin << offset_end << std::endl; } free(real_name); } // otherwise, print the whole line else { std::cerr << "[bt]: (" << i << ") " << messages[i] << std::endl; } } std::cerr << std::endl; free(messages); exit(EXIT_FAILURE); } 

    Cela pourrait valoir la peine de regarder Google Breakpad , un générateur de vidage sur incident multiplateforme et des outils pour traiter les vidages.

    Vous n’avez pas spécifié votre système d’exploitation, il est donc difficile de répondre. Si vous utilisez un système basé sur gnu libc, vous pouvez utiliser la fonction libc backtrace() .

    GCC a également deux fonctions intégrées qui peuvent vous aider, mais qui peuvent ou non être entièrement implémentées dans votre architecture, à savoir __builtin_frame_address et __builtin_return_address . Les deux veulent un niveau entier immédiat (par immédiat, je veux dire que cela ne peut pas être une variable). Si __builtin_frame_address pour un niveau donné est différent de zéro, il est prudent de saisir l’adresse de retour du même niveau.

    ulimit -c définit la limite de taille du fichier core sous Unix. Par défaut, la limite de taille du fichier principal est 0. Vous pouvez voir vos valeurs ulimit -a avec ulimit -a .

    De plus, si vous exécutez votre programme depuis gdb, cela arrêtera votre programme sur les “violations de segmentation” ( SIGSEGV , généralement lorsque vous avez accédé à un morceau de mémoire que vous n’aviez pas alloué) ou vous pouvez définir des points d’arrêt.

    ddd et nemiver sont des frontaux pour gdb, ce qui facilite le travail avec le novice.

    Certaines versions de libc contiennent des fonctions qui traitent des traces de stack; vous pourrez peut-être les utiliser:

    http://www.gnu.org/software/libc/manual/html_node/Backtraces.html

    Je me souviens d’avoir utilisé libunwind il y a longtemps pour obtenir des traces de stack, mais cela pourrait ne pas être pris en charge sur votre plate-forme.

    Il est important de noter qu’une fois que vous aurez généré un fichier core, vous devrez utiliser l’outil gdb pour le consulter. Pour que gdb donne un sens à votre fichier core, vous devez indiquer à gcc d’instrumenter le binary avec des symboles de débogage: pour ce faire, vous comstackz avec l’indicateur -g:

     $ g++ -g prog.cpp -o prog 

    Ensuite, vous pouvez soit définir “ulimit -c unlimited” pour le laisser vider un core, soit simplement exécuter votre programme dans gdb. J’aime la deuxième approche plus:

     $ gdb ./prog ... gdb startup output ... (gdb) run ... program runs and crashes ... (gdb) where ... gdb outputs your stack trace ... 

    J’espère que ça aide.

    J’ai examiné ce problème pendant un moment.

    Et profondément enfoui dans le README de Google Performance Tools

    http://code.google.com/p/google-perftools/source/browse/trunk/README

    parle de libunwind

    http://www.nongnu.org/libunwind/

    Aimerait entendre les opinions de cette bibliothèque.

    Le problème avec -rdynamic est qu’il peut augmenter la taille du fichier binary de manière relativement significative dans certains cas.

    Merci à enthousiaste d’avoir attiré mon attention sur l’utilitaire addr2line.

    J’ai écrit un script rapide et sale pour traiter le résultat de la réponse fournie ici (grâce à jschmier!) En utilisant l’utilitaire addr2line.

    Le script accepte un seul argument: le nom du fichier contenant la sortie de l’utilitaire de jschmier.

    La sortie devrait imprimer quelque chose comme ce qui suit pour chaque niveau de la trace:

     BACKTRACE: testExe 0x8A5db6b FILE: pathToFile/testExe.C:110 FUNCTION: testFunction(int) 107 108 109 int* i = 0x0; *110 *i = 5; 111 112 } 113 return i; 

    Code:

     #!/bin/bash LOGFILE=$1 NUM_SRC_CONTEXT_LINES=3 old_IFS=$IFS # save the field separator IFS=$'\n' # new field separator, the end of line for bt in `cat $LOGFILE | grep '\[bt\]'`; do IFS=$old_IFS # restore default field separator printf '\n' EXEC=`echo $bt | cut -d' ' -f3 | cut -d'(' -f1` ADDR=`echo $bt | cut -d'[' -f3 | cut -d']' -f1` echo "BACKTRACE: $EXEC $ADDR" A2L=`addr2line -a $ADDR -e $EXEC -pfC` #echo "A2L: $A2L" FUNCTION=`echo $A2L | sed 's/\.*//' | cut -d' ' -f2-99` FILE_AND_LINE=`echo $A2L | sed 's/.* at //'` echo "FILE: $FILE_AND_LINE" echo "FUNCTION: $FUNCTION" # print offending source code SRCFILE=`echo $FILE_AND_LINE | cut -d':' -f1` LINENUM=`echo $FILE_AND_LINE | cut -d':' -f2` if ([ -f $SRCFILE ]); then cat -n $SRCFILE | grep -C $NUM_SRC_CONTEXT_LINES "^ *$LINENUM\>" | sed "s/ $LINENUM/*$LINENUM/" else echo "File not found: $SRCFILE" fi IFS=$'\n' # new field separator, the end of line done IFS=$old_IFS # restore default field separator 
     ulimit -c unlimited 

    est une variable système qui permet de créer un core dump après le blocage de votre application. Dans ce cas, un montant illimité. Recherchez un fichier appelé core dans le même répertoire. Assurez-vous d’avoir compilé votre code avec les informations de débogage activées!

    Cordialement

    win: Que diriez-vous de StackWalk64 http://msdn.microsoft.com/en-us/library/ms680650.aspx

    Vous pouvez utiliser DeathHandler – petite classe C ++ qui fait tout pour vous, fiable.

    Oubliez le changement de vos sources et faites des hacks avec la fonction backtrace () ou les macroses – ce ne sont que des solutions médiocres.

    En tant que solution fonctionnant correctement, je conseillerais:

    1. Comstackz votre programme avec l’indicateur “-g” pour incorporer les symboles de débogage au format binary (ne vous inquiétez pas, cela n’affectera pas vos performances).
    2. Sur Linux, exécutez la commande suivante: “ulimit -c unlimited” – pour permettre au système de faire de gros vidages sur incident.
    3. Lorsque votre programme est bloqué, vous verrez dans le répertoire de travail le fichier “core”.
    4. Exécutez la prochaine commande pour imprimer la trace vers stdout: gdb -batch -ex “backtrace” ./your_program_exe ./core

    Cela affichera une trace lisible correcte de votre programme de manière lisible par l’homme (avec les noms de fichier source et les numéros de ligne). De plus, cette approche vous donnera la liberté d’automatiser votre système: ayez un script court qui vérifie si le processus a créé un core dump, puis envoyez des backtraces par courrier électronique aux développeurs, ou connectez-vous à un système de journalisation.

    Regarder:

    homme 3 backtrace

    Et:

     #include  int backtrace(void **buffer, int size); 

    Ce sont des extensions GNU.

    Je peux vous aider avec la version Linux: la fonction backtrace, backtrace_symbols et backtrace_symbols_fd peuvent être utilisées. Voir les pages de manuel correspondantes.

    Voir l’installation Stack Trace dans ACE (ADAPTIVE Communication Environment). Il est déjà écrit pour couvrir toutes les principales plates-formes (et plus encore). La bibliothèque est sous licence BSD afin que vous puissiez même copier / coller le code si vous ne souhaitez pas utiliser ACE.

    * nix: vous pouvez intercepter SIGSEGV (normalement ce signal est déclenché avant de planter) et conserver les informations dans un fichier. (en plus du fichier core que vous pouvez utiliser pour déboguer avec gdb par exemple).

    win: Cochez ceci depuis msdn.

    Vous pouvez également consulter le code chrome de Google pour voir comment il gère les pannes. Il a un bon mécanisme de gestion des exceptions.

    J’ai trouvé que la solution @tgamblin n’est pas complète. Il ne peut pas gérer avec stackoverflow. Je pense que par défaut, le gestionnaire de signal est appelé avec la même stack et SIGSEGV est lancé deux fois. Pour vous protéger, vous devez enregistrer une stack indépendante pour le gestionnaire de signaux.

    Vous pouvez vérifier cela avec le code ci-dessous. Par défaut, le gestionnaire échoue. Avec la macro définie STACK_OVERFLOW, tout va bien.

     #include  #include  #include  #include  #include  #include  #include  using namespace std; //#define STACK_OVERFLOW #ifdef STACK_OVERFLOW static char stack_body[64*1024]; static stack_t sigseg_stack; #endif static struct sigaction sigseg_handler; void handler(int sig) { cerr < < "sig seg fault handler" << endl; const int asize = 10; void *array[asize]; size_t size; // get void*'s for all entries on the stack size = backtrace(array, asize); // print out all the frames to stderr cerr << "stack trace: " << endl; backtrace_symbols_fd(array, size, STDERR_FILENO); cerr << "resend SIGSEGV to get core dump" << endl; signal(sig, SIG_DFL); kill(getpid(), sig); } void foo() { foo(); } int main(int argc, char **argv) { #ifdef STACK_OVERFLOW sigseg_stack.ss_sp = stack_body; sigseg_stack.ss_flags = SS_ONSTACK; sigseg_stack.ss_size = sizeof(stack_body); assert(!sigaltstack(&sigseg_stack, nullptr)); sigseg_handler.sa_flags = SA_ONSTACK; #else sigseg_handler.sa_flags = SA_RESTART; #endif sigseg_handler.sa_handler = &handler; assert(!sigaction(SIGSEGV, &sigseg_handler, nullptr)); cout << "sig action set" << endl; foo(); return 0; } 

    Je voudrais utiliser le code qui génère une trace de stack pour la fuite de mémoire dans Visual Leak Detector . Cela ne fonctionne que sur Win32.

    J’ai vu beaucoup de réponses ici effectuer un gestionnaire de signal et puis quitter. C’est la voie à suivre, mais souvenez-vous d’un fait très important: si vous voulez obtenir le core dump de l’erreur générée, vous ne pouvez pas appeler exit(status) . Appelez abort() place!

    Le nouveau roi en ville est arrivé https://github.com/bombela/backward-cpp

    1 en-tête à placer dans votre code et 1 bibliothèque à installer.

    Personnellement je l’appelle en utilisant cette fonction

     #include "backward.hpp" void stacker() { using namespace backward; StackTrace st; st.load_here(99); //Limit the number of trace depth to 99 st.skip_n_firsts(3);//This will skip some backward internal function from the trace Printer p; p.snippet = true; p.object = true; p.color = true; p.address = true; p.print(st, stderr); } 

    En plus des réponses ci-dessus, voici comment vous faites en sorte que Debian Linux OS génère un core dump

    1. Créez un dossier «coredumps» dans le dossier de base de l’utilisateur
    2. Allez dans /etc/security/limits.conf. Below the ‘ ‘ line, type “ soft core unlimited”, and “root soft core unlimited” if enabling core dumps for root, to allow unlimited space for core dumps.
    3. NOTE: “* soft core unlimited” does not cover root, which is why root has to be specified in its own line.
    4. To check these values, log out, log back in, and type “ulimit -a”. “Core file size” should be set to unlimited.
    5. Check the .bashrc files (user, and root if applicable) to make sure that ulimit is not set there. Otherwise, the value above will be overwritten on startup.
    6. Open /etc/sysctl.conf. Enter the following at the bottom: “kernel.core_pattern = /home//coredumps/%e_%t.dump”. (%e will be the process name, and %t will be the system time)
    7. Exit and type “sysctl -p” to load the new configuration Check /proc/sys/kernel/core_pattern and verify that this matches what you just typed in.
    8. Core dumping can be tested by running a process on the command line (“ &”), and then killing it with “kill -11 ”. If core dumping is successful, you will see “(core dumped)” after the segmentation fault indication.

    On Linux/unix/MacOSX use core files (you can enable them with ulimit or compatible system call ). On Windows use Microsoft error reporting (you can become a partner and get access to your application crash data).

    If your program crashes, it’s the operating system itself that generates crash dump information. If you’re using a *nix OS, you simply need to not prevent it from doing so (check out the ulimit command’s ‘coredump’ options).

    I forgot about the GNOME tech of “apport”, but I don’t know much about using it. It is used to generate stacktraces and other diagnostics for processing and can automatically file bugs. It’s certainly worth checking in to.

    As a Windows-only solution, you can get the equivalent of a stack trace (with much, much more information) using Windows Error Reporting . With just a few registry ensortinges, it can be set up to collect user-mode dumps :

    Starting with Windows Server 2008 and Windows Vista with Service Pack 1 (SP1), Windows Error Reporting (WER) can be configured so that full user-mode dumps are collected and stored locally after a user-mode application crashes. […]

    This feature is not enabled by default. Enabling the feature requires administrator privileges. To enable and configure the feature, use the following registry values under the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps key.

    You can set the registry ensortinges from your installer, which has the required privileges.

    Creating a user-mode dump has the following advantages over generating a stack trace on the client:

    • It’s already implemented in the system. You can either use WER as outlined above, or call MiniDumpWriteDump yourself, if you need more fine-grained control over the amount of information to dump. (Make sure to call it from a different process.)
    • Way more complete than a stack trace. Among others it can contain local variables, function arguments, stacks for other threads, loaded modules, and so on. The amount of data (and consequently size) is highly customizable.
    • No need to ship debug symbols. This both drastically decreases the size of your deployment, as well as makes it harder to reverse-engineer your application.
    • Largely independent of the comstackr you use. Using WER does not even require any code. Either way, having a way to get a symbol database (PDB) is very useful for offline analysis. I believe GCC can either generate PDB’s, or there are tools to convert the symbol database to the PDB format.

    Take note, that WER can only be sortingggered by an application crash (ie the system terminating a process due to an unhandled exception). MiniDumpWriteDump can be called at any time. This may be helpful if you need to dump the current state to diagnose issues other than a crash.

    Mandatory reading, if you want to evaluate the applicability of mini dumps:

    • Effective minidumps
    • Effective minidumps (Part 2)