Quando un processo ottiene SIGABRT (segnale 6)?


202

Quali sono gli scenari in cui un processo ottiene un SIGABRT in C ++? Questo segnale proviene sempre dall'interno del processo o può essere inviato da un processo all'altro?

C'è un modo per identificare quale processo sta inviando questo segnale?


3
Ci sono un paio di modi. Il modo più semplice, se hai scritto il programma, è registrare un gestore di segnale per SIGABRT che stampa tali informazioni e svuota i suoi flussi prima di tornare. Il secondo modo più semplice è eseguire il programma all'interno di strace. Il terzo modo più semplice è assicurarsi che il programma generi un file core quando si arresta in modo anomalo e scoprirlo tramite il dump principale.
Parthian Shot

Risposte:


195

abort()invia il SIGABRTsegnale al processo di chiamata , ecco come abort()funziona sostanzialmente.

abort()di solito viene chiamato dalle funzioni di libreria che rilevano un errore interno o un vincolo gravemente rotto. Ad esempio malloc()chiamerà abort()se le sue strutture interne sono danneggiate da un overflow dell'heap.


27
per me nella maggior parte dei casi SIGABRT è stato inviato libctentando di chiamare free()un puntatore non inizializzato / danneggiato
grandrew

Se ho da qualche parte nel codice, seppellito la pura chiamata di funzione virtuale all'interno del costruttore, potrebbe finire anche con il segnale SIGABRT? Sto chiedendo mentre vedo un errore che indica che ho una chiamata virtuale pura e la riga successiva mi dà un messaggio SIGABRT e l'applicazione si arresta in modo anomalo o viene chiusa dal sistema operativo. Grazie.
Hrvoje,

2
Su MacOS, abbiamo SIGABRT per l'apertura di circa 1000 handle di file senza chiuderli. Invece di deridere, i nostri test hanno estratto il file con un tipo di lettore più generico, che non ha alcun Close()metodo, quindi è stato dimenticato. Aveva una grande copertura però. : carrelli:
Zyl

52

SIGABRTè comunemente usato da libc e da altre librerie per interrompere il programma in caso di errori critici. Ad esempio, glibc invia un SIGABRTcaso di corruzione dell'heap rilevata double-free o di altro tipo.

Inoltre, la maggior parte delle assertimplementazioni si avvale SIGABRTin caso di affermazione fallita.

Inoltre, SIGABRTpuò essere inviato da qualsiasi altro processo come qualsiasi altro segnale. Naturalmente, il processo di invio deve essere eseguito come lo stesso utente o root.


49

È possibile inviare qualsiasi segnale a qualsiasi processo utilizzando l' kill(2)interfaccia:

kill -SIGABRT 30823

30823 è stato un dashprocesso che ho avviato, quindi ho potuto facilmente trovare il processo che volevo uccidere.

$ /bin/dash
$ Aborted

L' Abortedoutput è apparentemente comedash riporta un SIGABRT.

Può essere inviato direttamente a qualsiasi processo che utilizza kill(2), o un processo può inviare il segnale a se stesso tramite assert(3), abort(3)o raise(3).


17

Di solito succede quando si verifica un problema con l'allocazione della memoria.

Mi è successo quando il mio programma stava cercando di allocare un array con dimensioni negative.


14

C'è un'altra semplice causa in caso di c ++.

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

cioè l'ambito del thread è terminato ma ti sei dimenticato di chiamare

thread::join();

o

thread::detach();

7

GNU libc stamperà le informazioni /dev/ttyrelative ad alcune condizioni fatali prima di chiamare abort()(che quindi si innesca SIGABRT), ma se stai eseguendo il tuo programma come servizio o altrimenti non in una finestra terminale reale, questi messaggi potrebbero andare persi, perché non c'è tty per visualizzare i messaggi.

Vedi il mio post sul reindirizzamento di libc per scrivere su stderr invece di / dev / tty:

Cattura dei messaggi di errore libc, reindirizzamento da / dev / tty


4

Un caso in cui il processo prende SIGABRT da solo: Hrvoje ha menzionato un essere virtuale puro sepolto chiamato da ctor che genera un abort, ho ricreato un esempio per questo. Qui quando si deve costruire d, prima chiama la sua classe di base A ctor e passa il puntatore all'interno di se stesso. il ctor chiama puro metodo virtuale prima che la tabella fosse riempita con un puntatore valido, perché d non è ancora stato costruito.

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

compilare: g ++ -o aa aa.cpp

ulimit -c illimitato

corsa: ./aa

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

ora consente di vedere rapidamente il file principale e di confermare che SIGABRT è stato effettivamente chiamato:

gdb aa core

vedi regs:

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

codice di controllo:

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

Nel mio caso, era dovuto a un input in un array con un indice uguale alla lunghezza dell'array.

string x[5];

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

    cin>>x[i];

}

x [5] è in corso di accesso che non è presente.


1

Come "@sarnold", opportunamente sottolineato, qualsiasi processo può inviare segnali a qualsiasi altro processo, quindi, un processo può inviare SIGABORT ad un altro processo e in quel caso il processo di ricezione non è in grado di distinguere se il suo arrivo a causa della propria modifica di memoria ecc., o qualcun altro ha "unicastly", inviare ad esso.

In uno dei sistemi su cui ho lavorato c'è un rilevatore di deadlock che in realtà rileva se il processo sta uscendo da qualche compito dando il battito cardiaco o meno. In caso contrario, dichiara che il processo è in stato di deadlock e invia SIGABORT ad esso.

Volevo solo condividere questa prospettiva con riferimento alla domanda posta.


0

Darò la mia risposta dal punto di vista della programmazione competitiva (cp) , ma si applica anche ad altri settori.

Molte volte mentre si fa cp, i vincoli sono piuttosto grandi.

Ad esempio : avevo una domanda con una variabile N, M, Qtale 1 ≤ N, M, Q < 10^5.

L'errore facevo era io dichiarata 2D intero array di dimensione 10000 x 10000in C++e lottato con ilSIGABRT errore in Codechef per quasi 2 giorni.

Ora, se calcoliamo:

Dimensione tipica di un numero intero: 4 byte

Numero di celle nel nostro array: 10000 x 10000

Dimensione totale (in byte): 400000000 byte = 4 * 10 ^ 8 ≈ 400 MB

Le tue soluzioni a tali domande funzioneranno sul tuo PC (non sempre) in quanto possono permettersi queste dimensioni.

Ma le risorse nei siti di codifica (giudici online) sono limitate a pochi KB.

Quindi, l' SIGABRTerrore e altri errori simili.

Conclusione:

In tali domande, non dovremmo dichiarare un array o un vettore o qualsiasi altro DS di queste dimensioni, ma il nostro compito è rendere il nostro algoritmo così efficiente da funzionare senza di essi (DS) o con meno memoria.

PS : potrebbero esserci altri motivi per questo errore; sopra c'era uno di questi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.