Quand un processus obtient-il SIGABRT (signal 6)?


202

Quels sont les scénarios où un processus obtient un SIGABRT en C ++? Ce signal provient-il toujours du processus ou peut-il être envoyé d'un processus à un autre?

Existe-t-il un moyen d'identifier le processus qui envoie ce signal?


3
Il y a deux façons. La manière la plus simple, si vous avez écrit le programme, est d'enregistrer un gestionnaire de signaux pour SIGABRT qui imprime ces informations et vide ses flux avant de revenir. La deuxième façon la plus simple consiste à exécuter le programme dans strace. Le troisième moyen le plus simple consiste à s'assurer que le programme génère un fichier core lorsqu'il se bloque et à le découvrir via le vidage de mémoire.
Parthian Shot

Réponses:


195

abort()envoie le processus appelant le SIGABRTsignal, abort()voici comment fonctionne fondamentalement.

abort()est généralement appelé par des fonctions de bibliothèque qui détectent une erreur interne ou une contrainte sérieusement rompue. Par exemple malloc(), appellera abort()si ses structures internes sont endommagées par un débordement de tas.


27
pour moi dans la plupart des cas, SIGABRT a été envoyé en libcessayant d'appeler free()un pointeur non initialisé / corrompu
grandrew

Si j'ai quelque part dans le code, un appel de fonction virtuelle pur enterré à l'intérieur du constructeur, cela pourrait-il également se retrouver avec le signal SIGABRT? Je demande car je vois une erreur indiquant que j'ai un appel virtuel pur, et la ligne suivante me donne un message SIGABRT et l'application se bloque ou est fermée par le système d'exploitation. Merci.
Hrvoje

2
Sur MacOS, nous avons obtenu SIGABRT pour ouvrir environ 1000 descripteurs de fichiers sans les fermer. Au lieu de se moquer, nos tests ont résumé le fichier avec un type de lecteur plus générique, qui n'a pas de Close()méthode, donc il a été oublié. Avait une grande couverture cependant. : rolleyes:
Zyl

52

SIGABRTest couramment utilisé par libc et d'autres bibliothèques pour abandonner le programme en cas d'erreurs critiques. Par exemple, la glibc envoie un SIGABRTen cas de corruption de tas double ou autre détectée.

De plus, la plupart des assertimplémentations utilisent SIGABRTen cas d'échec d'une assertion.

En outre, SIGABRTpeut être envoyé à partir de tout autre processus comme tout autre signal. Bien sûr, le processus d'envoi doit s'exécuter en tant que même utilisateur ou racine.


49

Vous pouvez envoyer n'importe quel signal à n'importe quel processus en utilisant l' kill(2)interface:

kill -SIGABRT 30823

30823 était un dashprocessus que j'ai commencé, donc je pouvais facilement trouver le processus que je voulais tuer.

$ /bin/dash
$ Aborted

La Abortedsortie est apparemment comment dashrapporte un SIGABRT.

Il peut être envoyé directement à tout processus en utilisant kill(2), ou un processus peut envoyer le signal à lui - même via assert(3), abort(3)ou raise(3).


17

Cela se produit généralement en cas de problème d'allocation de mémoire.

Cela m'est arrivé lorsque mon programme essayait d'allouer un tableau avec une taille négative.


14

Il y a une autre cause simple en cas de c ++.

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

c.-à-d. portée du fil terminé mais vous avez oublié d'appeler

thread::join();

ou

thread::detach();

7

La libc GNU imprimera des informations /dev/ttyconcernant certaines conditions fatales avant d'appeler abort()(ce qui se déclenche ensuite SIGABRT), mais si vous exécutez votre programme en tant que service ou autrement dans une fenêtre de terminal réelle, ces messages peuvent être perdus, car il n'y a pas tty pour afficher les messages.

Voir mon article sur la redirection de libc pour écrire vers stderr au lieu de / dev / tty:

Attraper les messages d'erreur libc, rediriger depuis / dev / tty


4

Un cas où le processus obtient SIGABRT de lui-même: Hrvoje a mentionné qu'un virtuel pur enterré était appelé depuis ctor générant un abandon, j'ai recréé un exemple pour cela. Ici, lorsque d doit être construit, il appelle d'abord sa classe de base A ctor, et passe le pointeur intérieur à lui-même. A ctor appelle la méthode virtuelle pure avant que la table ne soit remplie avec un pointeur valide, car d n'est pas encore construit.

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

compiler: g ++ -o aa aa.cpp

ulimit -c illimité

exécuter: ./aa

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

permet maintenant de voir rapidement le fichier core, et de valider que SIGABRT a bien été appelé:

gdb aa core

voir les règlements:

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

vérifier le code:

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

Dans mon cas, c'était dû à une entrée dans un tableau à un indice égal à la longueur du tableau.

string x[5];

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

    cin>>x[i];

}

x [5] est en cours d'accès et n'est pas présent.


1

Comme "@sarnold", comme il a été judicieusement souligné, tout processus peut envoyer un signal à tout autre processus, par conséquent, un processus peut envoyer SIGABORT à un autre processus et dans ce cas, le processus de réception est incapable de distinguer si sa venue en raison de sa propre modification de mémoire etc, ou quelqu'un d'autre a "unicastly", envoyez-le.

Dans l'un des systèmes sur lesquels j'ai travaillé, il y a un détecteur de blocage qui détecte réellement si le processus sort d'une tâche en faisant battre le cœur ou non. Sinon, il déclare que le processus est dans un état de blocage et lui envoie SIGABORT.

Je voulais juste partager cette perspective en référence à la question posée.


0

Je donnerai ma réponse du point de vue de la programmation compétitive (cp) , mais elle s'applique également à d'autres domaines.

Plusieurs fois en faisant du cp, les contraintes sont assez importantes.

Par exemple : j'avais une question avec une variable N, M, Qtelle que 1 ≤ N, M, Q < 10^5.

L'erreur que je faisais était je déclarai un tableau 2D entier de taille 10000 x 10000dans C++et eu du mal avec l' SIGABRTerreur à Codechef pendant presque 2 jours.

Maintenant, si nous calculons:

Taille typique d'un entier: 4 octets

Nombre de cellules dans notre réseau: 10000 x 10000

Taille totale (en octets): 400000000 octets = 4 * 10 ^ 8 ≈ 400 Mo

Vos solutions à ces questions fonctionneront sur votre PC (pas toujours) car il peut se permettre cette taille.

Mais les ressources des sites de codage (juges en ligne) sont limitées à quelques Ko.

Par conséquent, l' SIGABRTerreur et d'autres erreurs de ce type.

Conclusion:

Dans de telles questions, nous ne devons pas déclarer un tableau ou un vecteur ou tout autre DS de cette taille, mais notre tâche est de rendre notre algorithme si efficace qu'il fonctionne sans eux (DS) ou avec moins de mémoire.

PS : Il peut y avoir d'autres raisons à cette erreur; ci-dessus était l'un d'eux.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.