Quels sont les scénarios dans lesquels 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 quel processus envoie ce signal?
abort()
envoie au processus appelant le signal SIGABRT
, voici comment abort()
fonctionne.
abort()
est généralement appelé par les fonctions de la 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.
Vous pouvez envoyer n'importe quel signal à n'importe quel processus à l'aide de l'interface kill(2)
:
kill -SIGABRT 30823
30823 était un processus dash
que j'avais commencé afin de pouvoir facilement trouver le processus que je voulais tuer.
$ /bin/dash
$ Aborted
La sortie Aborted
indique apparemment comment dash
rapporte un SIGABRT.
Il peut être envoyé directement à tout processus à l'aide de kill(2)
, ou un processus peut s'envoyer le signal via lui-même via assert(3)
, abort(3)
ou raise(3)
.
SIGABRT
est couramment utilisé par la libc et d'autres bibliothèques pour abandonner le programme en cas d'erreur critique. Par exemple, glibc envoie un SIGABRT
en cas de corruption détectée à double réserve ou autre.
De plus, la plupart des implémentations assert
utilisent SIGABRT
en cas d’échec de la déclaration.
De plus, SIGABRT
peut être envoyé à partir de tout autre processus, à l'instar de tout autre signal. Bien sûr, le processus d'envoi doit être exécuté avec le même utilisateur ou le même utilisateur root.
Cela se produit généralement lorsqu'il y a un problème d'allocation de mémoire.
Cela m'est arrivé lorsque mon programme tentait d'allouer un tableau de taille négative.
Il y a une autre cause simple dans le cas de c ++.
std::thread::~thread{
if((joinable ())
std::terminate ();
}
c'est-à-dire que la portée du fil est terminée mais que vous avez oublié d'appeler non plus
thread::join();
ou
thread::detach();
La GNU libc imprimera des informations à /dev/tty
concernant certaines conditions fatales avant d'appeler abort()
(qui déclenchera alors SIGABRT
), mais si vous exécutez votre programme en tant que service ou autrement pas dans une fenêtre de terminal réelle, ces messages peuvent être perdus, car il n’existe pas de terminal pour afficher les messages.
Voir mon post sur la redirection de libc pour écrire sur stderr au lieu de/dev/tty:
Un cas où le processus obtient SIGABRT de lui-même: Hrvoje a parlé d’un appel virtuel pur enterré 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, puis passe le pointeur interne à lui-même. L'acteur 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é
lancer: ./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 regs:
i r
rdx 0x6 6
rsi 0x69a 1690
rdi 0x69a 1690
rip 0x7feae3170c37
code de vérification:
dises 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
:)
Dans mon cas, cela était dû à une entrée dans un tableau à un index égal à la longueur du tableau.
string x[5];
for(int i=1; i<=5; i++){
cin>>x[i];
}
on accède à x [5] qui n'est pas présent.