Quando un processo ottiene SIGABRT (segnale 6)?

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?

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

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

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

Puoi inviare qualsiasi segnale a qualsiasi processo usando l’interfaccia kill(2) :

kill -SIGABRT 30823

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

 $ /bin/dash $ Aborted 

L’output interrotto è apparentemente come dash mostra un SIGABRT.

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

SIGABRT è comunemente usato da libc e da altre librerie per abortire il programma in caso di errori critici. Ad esempio, glibc invia un SIGABRT nel caso in cui SIGABRT rilevati SIGABRT di double-free o di heap.

Inoltre, la maggior parte delle implementazioni SIGABRT fa uso di SIGABRT in caso di affermazione fallita.

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.

Succede di solito quando c’è un problema con l’allocazione della memoria.

È successo a me quando il mio programma stava tentando di allocare un array con dimensioni negative.

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

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

vale a dire l’ambito del thread terminato, ma hai dimenticato di chiamare entrambi

 thread::join(); 

o

 thread::detach(); 

GNU libc stamperà le informazioni su /dev/tty riguardo alcune condizioni fatali prima di chiamare abort() (che quindi triggers SIGABRT ), ma se stai eseguendo il tuo programma come servizio o altrimenti non in una vera finestra di terminale, questo messaggio può perdersi, 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 messaggi di errore di libc, reindirizzamento da / dev / tty

Un caso in cui il processo ottiene SIGABRT da se stesso: Hrvoje ha menzionato un essere virtuale sepolto sepolto dal generatore che ha generato un aborto, ho ricreato un esempio per questo. Qui quando d deve essere costruito, prima chiama la sua class base A ctor e passa il puntatore interno 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 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

corri: ./aa

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

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

 gdb aa core 

guarda i reg:

 ir 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

🙂

Nel mio caso, era dovuto a un input in un array a 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.