¿Cuándo obtiene un proceso SIGABRT (señal 6)?


202

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

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


3
Hay un par de maneras. La forma más fácil, si escribió el programa, es registrar un controlador de señal para SIGABRT que imprima esa información y vacíe sus flujos antes de regresar. La segunda forma más fácil es ejecutar el programa dentro de strace. La tercera forma más fácil es asegurarse de que el programa genere un archivo central cuando se bloquea y averiguarlo a través del volcado del núcleo.
Parthian Shot

Respuestas:


195

abort()envía la SIGABRTseñal al proceso de llamada , así es como abort()funciona básicamente.

abort()Por lo general, se llama mediante funciones de biblioteca que detectan un error interno o alguna restricción seriamente rota. Por ejemplo malloc(), llamará abort()si sus estructuras internas están dañadas por un desbordamiento del montón.


27
para mí, en la mayoría de los casos, SIGABRT fue enviado al libcintentar llamar free()a un puntero no inicializado / dañado
nieto

Si tengo en algún lugar del código, llamada de función virtual pura enterrada desde dentro del constructor, ¿podría eso también terminar con la señal SIGABRT? Pregunto porque 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 el sistema operativo la cierra. Gracias.
Hrvoje

2
En MacOS, obtuvimos SIGABRT por abrir aproximadamente 1000 identificadores de archivos sin cerrarlos. En lugar de burlarse, nuestras pruebas abstrajeron el archivo con un tipo de lector más genérico, que no tiene Close()método, por lo que se olvidó. Aunque tenía una gran cobertura. : rolleyes:
Zyl

52

SIGABRTes comúnmente usado por libc y otras bibliotecas para abortar el programa en caso de errores críticos. Por ejemplo, glibc envía unSIGABRT en caso de que se detecte doble-libre u otros daños en el montón.

Además, la mayoría de las assertimplementaciones hacen uso deSIGABRT en caso de una afirmación fallida.

Además, SIGABRTse puede enviar 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.


49

Puede enviar cualquier señal a cualquier proceso utilizando la kill(2)interfaz:

kill -SIGABRT 30823

30823 fue un dashproceso que comencé, por lo que pude encontrar fácilmente el proceso que quería matar.

$ /bin/dash
$ Aborted

La Abortedsalida es al parecer la forma dashreporta un SIGABRT.

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


17

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

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


14

Hay otra causa simple en el caso de c ++.

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

es decir, el alcance del hilo terminó pero olvidó llamar

thread::join();

o

thread::detach();

7

GNU libc imprimirá información /dev/ttysobre algunas condiciones fatales antes de llamar abort()(que luego se dispara SIGABRT), pero si está ejecutando su programa como un servicio o no en una ventana de terminal real, este mensaje puede perderse, porque no hay tty para mostrar los mensajes.

Vea mi publicación sobre la redirección de libc para escribir en stderr en lugar de / dev / tty:

Capturando mensajes de error de libc, redirigiendo desde / dev / tty


4

Un caso en el que el proceso obtiene SIGABRT de sí mismo: Hrvoje mencionó sobre un ser virtual puro enterrado llamado desde ctor que genera 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 llenara con un puntero válido, porque d aún no está construida.

#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;
}

compilar: g ++ -o aa aa.cpp

ulimit -c ilimitado

ejecutar: ./aa

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

ahora veamos rápidamente el archivo central y validemos que SIGABRT realmente se llamó:

gdb aa core

ver reglas:

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

Código de verificación:

disas 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

:)


2

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

string x[5];

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

    cin>>x[i];

}

Se accede a x [5] que no está presente.


1

Como "@sarnold", señaló acertadamente, cualquier proceso puede enviar señal a cualquier otro proceso, por lo tanto, un proceso puede enviar SIGABORT a otro proceso y, en ese caso, el proceso de recepción no puede distinguir si se produce debido a su propio ajuste de memoria, etc., o alguien más tiene "unicastly", envíela.

En uno de los sistemas que trabajé hay un detector de punto muerto que realmente detecta si el proceso está saliendo de alguna tarea al dar latidos cardíacos o no. De lo contrario, declara que el proceso está en estado de punto muerto y le envía SIGABORT.

Solo quería compartir esta perspectiva con referencia a la pregunta formulada.


0

Daré mi respuesta desde una perspectiva de programación competitiva (cp) , pero también se aplica a otros dominios.

Muchas veces al hacer cp, las restricciones son bastante grandes.

Por ejemplo : tuve una pregunta con variables N, M, Qcomo esa 1 ≤ N, M, Q < 10^5.

El error que estaba cometiendo fue declarar una matriz de tamaño entero 2D 10000 x 10000en C++y luché con el SIGABRTerror en Codechef durante casi 2 días.

Ahora, si calculamos:

Tamaño típico de un entero: 4 bytes

No. de celdas en nuestra matriz: 10000 x 10000

Tamaño total (en bytes): 400000000 bytes = 4 * 10 ^ 8 ≈ 400 MB

Sus soluciones a tales preguntas funcionarán en su PC (no siempre) ya que puede permitirse este tamaño.

Pero los recursos en los sitios de codificación (jueces en línea) están limitados a unos pocos KB.

Por lo tanto, el SIGABRTerror y otros errores similares.

Conclusión:

En tales preguntas, no debemos declarar una matriz o vector o cualquier otro DS de este tamaño, pero nuestra tarea es hacer que nuestro algoritmo sea tan eficiente que funcione sin ellos (DS) o con menos memoria.

PD : puede haber otras razones para este error; arriba era uno de ellos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.