Cómo provocar un volcado de núcleo mediante programación en C / C ++

93

Me gustaría forzar un volcado de memoria en una ubicación específica en mi aplicación C ++.

Sé que puedo hacerlo haciendo algo como:

int * crash = NULL;
*crash = 1;

Pero me gustaría saber si hay una forma más limpia.

Estoy usando Linux por cierto.

hhafez
fuente
18
¿Una forma "más limpia" de volcado de núcleos? .... bueno;)
DO.
5
Esto es tierno. Mejor aún, use un booleano (enumeración en c?) ... if ( crash = TRUE) {/ OH SHI ... * /}
Ape-inago
3
Por cierto, ese método no funciona en todos los UNIX. HPUX, por ejemplo, le permite leer y escribir NULL con impunidad (afortunadamente, esto es configurable).
paxdiablo
1
Acabo de aprender como 3 o 4 grandes cosas nuevas. Gracias.
Trevor Boyd Smith
@pax esa es más una razón para encontrar una forma genérica;) Gracias
hhafez

Respuestas:

76

El aumento de la señal número 6 ( SIGABRTen Linux) es una forma de hacerlo (aunque tenga en cuenta que no se requiere que SIGABRT sea ​​6 en todas las implementaciones POSIX, por lo que es posible que desee usar el SIGABRTvalor en sí mismo si esto es algo diferente a quick'n 'código de depuración sucio).

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

Llamar abort()también causará un volcado del núcleo, e incluso puede hacer esto sin terminar su proceso llamando fork()seguido de solo abort()en el niño; consulte esta respuesta para obtener más detalles.

paxdiablo
fuente
7
No se requiere que SIGABRT sea la señal número 6 (aunque a menudo lo es, y es, específicamente, en Linux).
Jonathan Leffler
4
No, tienes razón, no lo es, pero no suelo preocuparme demasiado por la exactitud del código de depuración. Si eso se escapa a la naturaleza, la limpieza de mi código es la menor de mis preocupaciones :-)
paxdiablo
2
Llamar a abort () puede ser inútil en algunas arquitecturas con algunos compiladores y algunas bibliotecas C (como gcc y glibc o uClibc en ARM) porque la función abort () se declara con un atributo noreturn y el compilador optimiza totalmente toda la información de retorno, lo que hace que el archivo principal sea inutilizable. No puede rastrearlo más allá de la llamada a raise () o abortar (). Así que es mucho mejor llamar a raise (SIGABRT) directamente o kill (getpid (), SIGABRT), que es prácticamente lo mismo.
Alexander Amelkin
3
Lo siento, en ARM sucede lo mismo incluso con la subida (SIGABRT). Entonces, la única forma de producir un archivo central rastreable es kill (getpid (), SIGABRT)
Alexander Amelkin
La sugerencia ulimit -c unlimitedde la respuesta de Suvesh Pratapa, me ayudó mucho para esta respuesta.
Boris Däppen
74

Hace unos años, Google lanzó la biblioteca coredumper .

Visión general

La biblioteca coredumper se puede compilar en aplicaciones para crear volcados del núcleo del programa en ejecución, sin terminar. Admite volcados de núcleo de subproceso único y múltiple, incluso si el kernel no admite de forma nativa archivos de núcleo de subproceso múltiple.

Coredumper se distribuye según los términos de la licencia BSD.

Ejemplo

Este no es de ninguna manera un ejemplo completo; simplemente le da una idea de cómo se ve la API de coredumper.

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

No es lo que estabas pidiendo, pero tal vez sea incluso mejor :)

efímero
fuente
3
Inicialmente estaba bastante emocionado cuando encontré esta respuesta. Pero el dumper de núcleos se ve bastante viejo y decrépito estos días. Incluso hay indicios de que ya no funciona en los kernels de Linux contemporáneos: stackoverflow.com/questions/38314020/…
jefe2000
37

Como se enumera en la página de manual de la señal , cualquier señal con la acción listada como 'núcleo' forzará un volcado de núcleo. Algunos ejemplos son:

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

Asegúrese de habilitar los volcados de memoria:

ulimit -c unlimited
Suvesh Pratapa
fuente
Gracias, su comentario sobre la habilitación de volcados de memoria ulimit -c unlimitedayudó.
¿Cómo establecería ulimit desde dentro del código? @ ks1322
Karan Joisher
@KaranJoisher Eso probablemente valga otra pregunta en sí mismo, pero en resumen, puede usar setrlimit(RLIMIT_CORE, &core_limits);disponible a través de #include <sys/resource.h>. Crea una estructura de tipo rlimity luego establece los miembros rlim_cury rlim_max.
Brent escribe código
31
#include <stdlib.h>   // C
//#include <cstdlib>  // C++

void core_dump(void)
{
    abort();
}
Jonathan Leffler
fuente
3
¿Por qué no llamar abort()directamente?
DepressedDaniel
6

Otra forma de generar un volcado de memoria:

$ bash
$ kill -s SIGSEGV $$

Simplemente cree una nueva instancia de bash y elimínela con la señal especificada. El $$es el PID del shell. De lo contrario, está eliminando su bash actual y se cerrará la sesión, se cerrará o desconectará la terminal.

$ bash 
$ kill -s SIGABRT $$
$ bash
$ kill -s SIGFPE $$
Zonk
fuente
¡Muy simple y útil!
firo
1
Me gusta ese también. Incluso se puede simplificar a bash -c 'kill -SIGSEGV $$'.
Christian Krause
4

Puedes usar kill (2) para enviar la señal.

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

Entonces,

kill(getpid(), SIGSEGV);
Eugene Yokota
fuente
Sip. Agregó eso a la respuesta.
Eugene Yokota
2

A veces, puede ser apropiado hacer algo como esto:

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 problema con este enfoque simple es que solo se realizará el coredumped en un hilo.

rka444
fuente
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;
 }

usa este enfoque donde quieras :)

karthik339
fuente
0
#include <assert.h>
.
.
.
     assert(!"this should not happen");
sigjuice
fuente
Probablemente necesite deshacerse de NDEBUG para que esta afirmación en particular esté activa incluso cuando otras afirmaciones no lo estén.
Rhys Ulerich