2010-08-05 3 views
133

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 questo segnale da un processo all'altro?Quando un processo ottiene SIGABRT (segnale 6)?

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

+2

Ci sono un paio di modi. Il modo più semplice, se hai scritto il programma, è quello di registrare un gestore di segnali per SIGABRT che stampi tali informazioni e ne scarichi i 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 blocca e scoprirlo tramite il core dump. –

risposta

134

abort() invia il processo di chiamata il segnale SIGABRT, questo è il modo in cui funziona abort() fondamentalmente.

abort() viene in genere chiamato da funzioni di libreria che rilevano un errore interno o un vincolo gravemente interrotto. Ad esempio, malloc() chiamerà abort() se le sue strutture interne sono danneggiate da un overflow di heap.

+14

per me nella maggior parte dei casi SIGABRT è stato inviato da 'libc' cercando di chiamare' free() 'su un puntatore non inizializzato/danneggiato – grandrew

+0

Se ho qualche parte nel codice, sepolto la pura chiamata di funzione virtuale dall'interno del costruttore, potrebbe anche finire con il segnale SIGABRT? Sto chiedendo come sto vedendo un errore affermando che ho una chiamata virtuale pura, e la riga successiva mi dà un messaggio SIGABRT e l'applicazione si blocca o viene chiusa dal sistema operativo. Grazie. – Hrvoje

44

di inviare un segnale a qualsiasi processo che utilizza l'interfaccia kill(2):

kill -SIGABRT 30823

30823 è stato un processo dash ho iniziato, così ho potuto facilmente trovare il processo che volevo uccidere.

$ /bin/dash 
$ Aborted 

L'Aborted uscita è apparentemente come dash segnala un SIGABRT.

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

37

SIGABRT è comunemente utilizzato da libc e da altre librerie per interrompere il programma in caso di errori critici. Ad esempio, glibc invia un SIGABRT in caso di danni a doppio-libero o ad altro heap rilevati.

Inoltre, la maggior parte delle implementazioni "assert" fa uso di SIGABRT in caso di affermazione non riuscita.

Inoltre, SIGABRT può essere inviato da qualsiasi altro processo come qualsiasi altro segnale. Ovviamente, il processo di invio deve essere eseguito come utente o root.

12

Accade solitamente quando c'è un problema con l'allocazione della memoria.

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

3

La GNU libc si stampare le informazioni per /dev/tty riguardanti alcune condizioni fatali prima di chiamare abort() (che poi innesca SIGABRT), ma se si esegue il programma come un servizio o comunque non in una vera e propria finestra di terminale, questi messaggi possono perdersi, perché non c'è tty per visualizzare i messaggi.

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

Catching libc error messages, redirecting from /dev/tty

6

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

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

, ad es.portata di filo finito ma si è dimenticato di chiamare sia

thread::join(); 

o

thread::detach(); 
1

Nel mio caso, era dovuta ad un ingresso in una matrice a un indice pari alla lunghezza della matrice.

string x[5]; 

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

    cin>>x[i]; 

} 

x [5] accede a quale non è presente.

2

Un caso in cui il processo ottiene SIGABRT da solo: Hrvoje ha menzionato un seppellimento di un vero e proprio virtuale sepolto dal generatore che ha generato un annullamento, ho ricreato un esempio per questo. Qui quando d deve essere costruito, prima chiama la sua classe base A ctor, e passa all'interno del puntatore a se stesso. l'A ctor chiama il metodo virtuale puro 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; 
} 

compilazione: g ++ -o aa aa.cpp

ulimit -c unlimited

run: ./aa

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

Ora consente di vedere rapidamente il file core, e convalidare SIGABRT è stato effettivamente chiamato:

gdb aa core 

vedere REGS: codice

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

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

:)