Comment provoquer par programme un vidage de mémoire en C / C ++

93

Je voudrais forcer un vidage de mémoire à un emplacement spécifique dans mon application C ++.

Je sais que je peux le faire en faisant quelque chose comme:

int * crash = NULL;
*crash = 1;

Mais j'aimerais savoir s'il existe un moyen plus propre?

J'utilise Linux au fait.

Hhafez
la source
18
Une façon "plus propre" de vidage de mémoire? .... bon;)
JO.
5
C'est mignon. Mieux vaut encore utiliser un booléen (enum en c?) ... if ( crash = TRUE) {/ OH SHI ... * /}
Ape-inago
3
BTW, cette méthode ne fonctionne pas dans tous les UNIX. HPUX, pour sa part, vous permet de lire et d'écrire NULL en toute impunité (heureusement, c'est configurable).
paxdiablo
1
Je viens d'apprendre 3 ou 4 nouvelles choses formidables. Merci.
Trevor Boyd Smith le
@pax c'est plus une raison de trouver un moyen générique;) Merci
hhafez

Réponses:

76

L'augmentation du signal numéro 6 ( SIGABRTsous Linux) est une façon de le faire (mais gardez à l'esprit que SIGABRT n'est pas obligé d'être 6 dans toutes les implémentations POSIX, vous pouvez donc utiliser la SIGABRTvaleur elle-même si c'est autre chose que quick'n 'code de débogage sale).

#include <signal.h>
: : :
raise (SIGABRT);

L'appel abort()provoquera également un vidage de mémoire, et vous pouvez même le faire sans terminer votre processus en appelant fork()suivi de abort()dans l'enfant uniquement - voir cette réponse pour plus de détails.

paxdiablo
la source
7
SIGABRT n'est pas obligé d'être le signal numéro 6 (bien qu'il soit souvent - et est, en particulier, sous Linux).
Jonathan Leffler
4
Non, vous avez raison, ce n'est pas le cas, mais j'ai tendance à ne pas trop m'inquiéter de l'exactitude du code de débogage. Si cela s'échappe dans la nature, la propreté de mon code est le
cadet
2
L'appel de abort () peut être inutile sur certaines architectures avec certains compilateurs et certaines bibliothèques C (comme gcc et glibc ou uClibc sur ARM) car la fonction abort () est déclarée avec un attribut noreturn et le compilateur optimise totalement toutes les informations de retour, ce qui rend le fichier core inutilisable. Vous ne pouvez pas le suivre au-delà de l'appel à lever () ou à abandonner () lui-même. Il est donc préférable d'appeler directement rise (SIGABRT) ou kill (getpid (), SIGABRT), ce qui est pratiquement le même.
Alexander Amelkin
3
Désolé, sur ARM, la même chose se produit même avec une augmentation (SIGABRT). Donc, le seul moyen de produire un fichier core traçable est kill (getpid (), SIGABRT)
Alexander Amelkin
L'allusion à la ulimit -c unlimitedréponse de Suvesh Pratapa m'a beaucoup aidé pour cette réponse.
Boris Däppen
74

Il y a quelques années, Google a publié la bibliothèque coredumper .

Aperçu

La bibliothèque coredumper peut être compilée dans des applications pour créer des vidages de mémoire du programme en cours d'exécution - sans s'arrêter. Il prend en charge les vidages de mémoire à un et à plusieurs threads, même si le noyau ne prend pas en charge nativement les fichiers de base à plusieurs threads.

Coredumper est distribué sous les termes de la licence BSD.

Exemple

Ce n'est en aucun cas un exemple complet; cela vous donne simplement une idée de ce à quoi ressemble l'API coredumper.

#include <google/coredumper.h>
...
WriteCoreDump('core.myprogram');
/* Keep going, we generated a core file,
 * but we didn't crash.
 */

Ce n'est pas ce que vous demandiez, mais c'est peut-être encore mieux :)

éphémère
la source
3
J'étais au départ assez excité quand j'ai rencontré cette réponse. Mais le dumper de base a l'air assez vieux et décrépit ces jours-ci. Il y a même une indication que cela ne fonctionne plus sur les noyaux Linux contemporains: stackoverflow.com/questions/38314020
...
37

Comme indiqué dans la page de manuel signal , tout signal avec l'action répertoriée comme «core» forcera un vidage de mémoire. Quelques exemples sont:

SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGSEGV      11       Core    Invalid memory reference

Assurez-vous que vous activez les vidages de mémoire:

ulimit -c unlimited
Suvesh Pratapa
la source
Merci, votre remarque sur l'activation des vidages de mémoire avec ulimit -c unlimitedaidé.
Comment définiriez-vous l'ulimit à partir du code? @ ks1322
Karan Joisher
@KaranJoisher Cela vaut probablement une autre question en soi, mais en bref, vous pouvez utiliser setrlimit(RLIMIT_CORE, &core_limits);disponible via #include <sys/resource.h>. Vous créez une structure de type rlimit, puis définissez les membres rlim_curet rlim_max.
Brent écrit le code
31
#include <stdlib.h>   // C
//#include <cstdlib>  // C++

void core_dump(void)
{
    abort();
}
Jonathan Leffler
la source
3
Pourquoi ne pas simplement appeler abort()directement?
DepressedDaniel
6

Une autre façon de générer un vidage de mémoire:

$ bash
$ kill -s SIGSEGV $$

Créez simplement une nouvelle instance du bash et tuez-la avec le signal spécifié. Le $$est le PID du shell. Sinon, vous tuez votre bash actuel et serez déconnecté, le terminal fermé ou déconnecté.

$ bash 
$ kill -s SIGABRT $$
$ bash
$ kill -s SIGFPE $$
Zonk
la source
Très simple et utile!
firo
1
J'aime celui-là aussi. Il peut même être simplifié en bash -c 'kill -SIGSEGV $$'.
Christian Krause
4

Vous pouvez utiliser kill (2) pour envoyer un signal.

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

Alors,

kill(getpid(), SIGSEGV);
Eugene Yokota
la source
Ouaip. Ajouté cela à la réponse.
Eugene Yokota
2

Parfois, il peut être approprié de faire quelque chose comme ceci:

int st = 0;
pid_t p = fork();

if (!p) {
    signal(SIGABRT, SIG_DFL);
    abort(); // having the coredump of the exact copy of the calling thread
} else {
    waitpid(p, &st, 0); // rip the zombie
}

// here the original process continues to live

Un problème avec cette approche simple est qu'un seul thread sera coredumpé.

rka444
la source
1
 #include <stdio.h>
 #include <stdlib.h>
 int main()
 {
   printf("\n");
   printf("Process is aborting\n");
   abort();
   printf("Control not reaching here\n");
   return 0;
 }

utilisez cette approche où vous voulez :)

karthik339
la source
0
#include <assert.h>
.
.
.
     assert(!"this should not happen");
Sigjuice
la source
Il faut probablement utiliser NDEBUG pour que cette assertion particulière soit active même lorsque d'autres assertions ne le sont pas.
Rhys Ulerich