2010-08-05 24 views
133

¿Cuáles son los escenarios donde un proceso obtiene un SIGABRT en C++? ¿Esta señal siempre proviene del proceso o puede enviarse esta señal de un proceso a otro?¿Cuándo obtiene un proceso SIGABRT (señal 6)?

¿Hay alguna manera de identificar qué proceso está enviando esta señal?

+2

Hay un par de formas. La forma más fácil, si escribió el programa, es registrar un manejador de señal para SIGABRT que imprime esa información y vacía sus transmisiones antes de regresar. La segunda forma más fácil es ejecutar el programa dentro de la ley. La tercera forma más sencilla es garantizar que el programa genere un archivo central cuando se bloquea y que se descubra a través del volcado del núcleo. –

Respuesta

134

abort() envía el proceso de llamada a la señal SIGABRT, así es como funciona abort().

abort() suele ser llamado por funciones de la biblioteca que detectan un error interno o alguna restricción gravemente dañada. Por ejemplo, malloc() llamará al abort() si sus estructuras internas están dañadas por un desbordamiento de pila.

+14

para mí en la mayoría de los casos SIGABRT fue enviado por 'libc' tratando de llamar a' free() 'en un puntero no inicializado/corrupto – grandrew

+0

Si tengo algún lugar en el código, enterré la llamada de función virtual pura dentro del constructor, ¿podría eso? también terminan con la señal SIGABRT? Pregunto cuando veo un error que indica que tengo una llamada virtual pura, y la siguiente línea me da un mensaje SIGABRT y la aplicación se bloquea o se cierra por el sistema operativo. Gracias. – Hrvoje

44

Para enviar cualquier señal a cualquier proceso mediante la interfaz kill(2):

kill -SIGABRT 30823

30823 fue un proceso dash empecé, así que podría fácilmente encontrar el proceso que quería matar.

$ /bin/dash 
$ Aborted 

La salida Aborted es aparentemente la forma dash reporta un SIGABRT.

puede ser enviado directamente a cualquier proceso utilizando kill(2), o un proceso puede enviar la señal a sí mismo a través assert(3), abort(3), o raise(3).

37

SIGABRT es comúnmente utilizado por libc y otras bibliotecas para abortar el progamm en caso de errores críticos. Por ejemplo, glibc envía un SIGABRT en caso de corrupción detectada de doble libre u otra corrupción de montón.

Además, la mayoría de las implementaciones de "assert" hacen uso de SIGABRT en caso de una afirmación fallida. También puede enviar SIGABRT desde cualquier otro proceso como cualquier otra señal. Por supuesto, el proceso de envío debe ejecutarse como el mismo usuario o raíz.

12

Suele suceder cuando hay un problema con la asignación de memoria.

Me sucedió cuando mi programa intentaba asignar una matriz con tamaño negativo.

3

El GNU libc imprimirá la información a /dev/tty en relación con algunas enfermedades mortales antes de que llama abort() (lo cual dispara SIGABRT), pero si está ejecutando su programa como un servicio o de lo contrario no en una ventana de terminal real, estos mensajes pueden perderse, porque no hay tty para mostrar los mensajes.

Ver mi post sobre la reorientación de libc escribir en stderr en lugar de/dev/TTY:

Catching libc error messages, redirecting from /dev/tty

6

Hay otra causa simple en caso de C++.

std::thread::~thread{ 
    if((joinable()) 
     std::terminate(); 
} 

i.e.ámbito de hilo terminó pero se olvidó de llamar a cualquiera

thread::join(); 

o

thread::detach(); 
1

En mi caso, se debió a una entrada en una matriz con un índice igual a la longitud de la matriz.

string x[5]; 

for(int i=1; i<=5; i++){ 

    cin>>x[i]; 

} 

x [5] se está accediendo que no está presente.

2

Un caso cuando el proceso obtiene SIGABRT de sí mismo: Hrvoje mencionó acerca de un ser virtual puro enterrado llamado desde ctor que generaba un aborto, recreé un ejemplo para esto. Aquí cuando se va a construir d, primero llama a su clase base A ctor, y pasa el puntero interno a sí mismo. el Actor llama al método virtual puro antes de que la tabla se haya llenado con un puntero válido, porque d aún no está construido.

#include<iostream> 
using namespace std; 
class A { 
public: 
A(A *pa){pa->f();} 
virtual void f()=0; 
}; 
class D : public A { 
public: 
D():A(this){} 
virtual void f() {cout<<"D::f\n";} 
}; 
int main(){ 
D d; 
A *pa = &d; 
pa->f(); 
return 0; 
} 

de compilación: g ++ -o aa aa.cpp

ulimit -c unlimited

de ejecución: ./aa

pure virtual method called 
terminate called without an active exception 
Aborted (core dumped) 

Ahora vamos a ver rápidamente el archivo central, y validar que SIGABRT fue llamado:

gdb aa core 

ver regs: Código

i r 
rdx   0x6  6 
rsi   0x69a 1690 
rdi   0x69a 1690 
rip   0x7feae3170c37 

cheque:

DISA 0x7feae3170c37

mov $0xea,%eax = 234 <- this is the kill syscall, sends signal to process 
syscall <----- 

http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

234 sys_tgkill pid_t TGID pid_t pid int sig = 6 = SIGABRT

:)

Cuestiones relacionadas