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?
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.
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.
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).
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:
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>usingnamespace std;class A {public:
A(A *pa){pa->f();}virtualvoid f()=0;};class D :public A {public:
D():A(this){}virtualvoid f(){cout<<"D::f\n";}};int main(){
D d;
A *pa =&d;
pa->f();return0;}
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 0x66
rsi 0x69a1690
rdi 0x69a1690
rip 0x7feae3170c37
vérifier le code:
disas 0x7feae3170c37
mov $0xea,%eax =234<-this is the kill syscall, sends signal to process
syscall <-----
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.
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.
Réponses:
abort()
envoie le processus appelant leSIGABRT
signal,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 exemplemalloc()
, appelleraabort()
si ses structures internes sont endommagées par un débordement de tas.la source
libc
essayant d'appelerfree()
un pointeur non initialisé / corrompuClose()
méthode, donc il a été oublié. Avait une grande couverture cependant. : rolleyes:SIGABRT
est couramment utilisé par libc et d'autres bibliothèques pour abandonner le programme en cas d'erreurs critiques. Par exemple, la glibc envoie unSIGABRT
en cas de corruption de tas double ou autre détectée.De plus, la plupart des
assert
implémentations utilisentSIGABRT
en cas d'échec d'une assertion.En outre,
SIGABRT
peut ê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.la source
Vous pouvez envoyer n'importe quel signal à n'importe quel processus en utilisant l'
kill(2)
interface:kill -SIGABRT 30823
30823 était un
dash
processus que j'ai commencé, donc je pouvais facilement trouver le processus que je voulais tuer.La
Aborted
sortie est apparemment commentdash
rapporte un SIGABRT.Il peut être envoyé directement à tout processus en utilisant
kill(2)
, ou un processus peut envoyer le signal à lui - même viaassert(3)
,abort(3)
ouraise(3)
.la source
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.
la source
Il y a une autre cause simple en cas de c ++.
c.-à-d. portée du fil terminé mais vous avez oublié d'appeler
ou
la source
La libc GNU imprimera des informations
/dev/tty
concernant certaines conditions fatales avant d'appelerabort()
(ce qui se déclenche ensuiteSIGABRT
), 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
la source
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.
compiler: g ++ -o aa aa.cpp
ulimit -c illimité
exécuter: ./aa
permet maintenant de voir rapidement le fichier core, et de valider que SIGABRT a bien été appelé:
voir les règlements:
vérifier le code:
disas 0x7feae3170c37
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
:)
la source
Dans mon cas, c'était dû à une entrée dans un tableau à un indice égal à la longueur du tableau.
x [5] est en cours d'accès et n'est pas présent.
la source
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.
la source
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, Q
telle que1 ≤ N, M, Q < 10^5
.L'erreur que je faisais était je déclarai un tableau 2D entier de taille
10000 x 10000
dansC++
et eu du mal avec l'SIGABRT
erreur à Codechef pendant presque 2 jours.Maintenant, si nous calculons:
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'
SIGABRT
erreur 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.
la source