Wann erhält ein Prozess SIGABRT (Signal 6)?

202

In welchen Szenarien erhält ein Prozess in C ++ ein SIGABRT? Kommt dieses Signal immer aus dem Prozess oder kann dieses Signal von einem Prozess zum anderen gesendet werden?

Gibt es eine Möglichkeit zu identifizieren, welcher Prozess dieses Signal sendet?

Shree
quelle
3
Es gibt verschiedene Möglichkeiten. Wenn Sie das Programm geschrieben haben, ist es am einfachsten, einen Signalhandler für SIGABRT zu registrieren, der diese Informationen ausdruckt und seine Streams löscht, bevor Sie zurückkehren. Der zweit einfachste Weg ist, das Programm innerhalb von Strace auszuführen. Der dritte einfachste Weg besteht darin, sicherzustellen, dass das Programm beim Absturz eine Kerndatei generiert und dies über den Kernspeicherauszug herausfindet.
Parthian Shot

Antworten:

194

abort()Sendet dem aufrufenden Prozess das SIGABRTSignal, so funktioniert das abort()grundsätzlich.

abort()wird normalerweise von Bibliotheksfunktionen aufgerufen, die einen internen Fehler oder eine ernsthaft fehlerhafte Einschränkung erkennen. Zum Beispiel malloc()wird aufgerufen, abort()wenn seine internen Strukturen durch einen Heap-Überlauf beschädigt werden.

Nordischer Mainframe
quelle
27
Für mich wurde SIGABRT in den meisten Fällen gesendet, indem libcversucht wurde, free()einen nicht initialisierten / beschädigten Zeiger
aufzurufen
Wenn ich irgendwo im Code einen rein virtuellen Funktionsaufruf aus dem Konstruktor vergraben habe, könnte das dann auch mit dem SIGABRT-Signal enden? Ich frage, während ich einen Fehler sehe, der besagt, dass ich einen reinen virtuellen Anruf habe, und die nächste Zeile gibt mir eine SIGABRT-Nachricht und die Anwendung stürzt entweder ab oder wird vom Betriebssystem geschlossen. Vielen Dank.
Hrvoje
2
Unter MacOS haben wir SIGABRT zum Öffnen von ungefähr 1000 Dateihandles erhalten, ohne sie zu schließen. Anstatt zu verspotten, haben unsere Tests die Datei mit einem allgemeineren Lesertyp abstrahiert, der keine Close()Methode hat, sodass sie vergessen wurde. Hatte aber eine großartige Berichterstattung. : rolleyes:
Zyl
51

SIGABRTwird häufig von libc und anderen Bibliotheken verwendet, um das Programm bei kritischen Fehlern abzubrechen. Zum Beispiel sendet glibc SIGABRTim Falle einer erkannten Double-Free- oder anderen Heap-Beschädigung eine.

Außerdem verwenden die meisten assertImplementierungen SIGABRTim Falle einer fehlgeschlagenen Zusicherung.

Darüber hinaus SIGABRTkann von jedem anderen Prozess wie jedes andere Signal gesendet werden. Natürlich muss der Sendevorgang als derselbe Benutzer oder Root ausgeführt werden.

IanH
quelle
49

Sie können jedes Signal über die kill(2)Schnittstelle an jeden Prozess senden :

kill -SIGABRT 30823

30823 war ein dashProzess, den ich gestartet habe, sodass ich den Prozess, den ich töten wollte, leicht finden konnte.

$ /bin/dash
$ Aborted

Die AbortedAusgabe ist anscheinend, wie dashein SIGABRT gemeldet wird.

Es kann direkt unter Verwendung von einem Prozess gesendet werden kill(2), oder ein Verfahren , kann das Signal an sich selbst über senden assert(3), abort(3)oder raise(3).

Sarnold
quelle
17

Dies tritt normalerweise auf, wenn ein Problem mit der Speicherzuordnung vorliegt.

Es ist mir passiert, als mein Programm versucht hat, ein Array mit negativer Größe zuzuweisen.

Mig
quelle
14

Es gibt eine andere einfache Ursache im Fall von c ++.

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

dh Umfang des Threads beendet, aber Sie haben vergessen, entweder aufzurufen

thread::join();

oder

thread::detach();
Sudip Bhattarai
quelle
7

Die GNU libc druckt Informationen zu /dev/ttyeinigen schwerwiegenden Zuständen aus, bevor sie aufgerufen wird abort()(was dann ausgelöst wird SIGABRT). Wenn Sie Ihr Programm jedoch als Dienst ausführen oder auf andere Weise nicht in einem echten Terminalfenster, können diese Meldungen verloren gehen, da keine vorhanden sind tty, um die Nachrichten anzuzeigen.

Siehe meinen Beitrag zum Umleiten von libc zum Schreiben an stderr anstelle von / dev / tty:

Abrufen von libc-Fehlermeldungen, Umleiten von / dev / tty

Mark Lakata
quelle
4

Ein Fall, in dem ein Prozess SIGABRT von sich selbst erhält: Hrvoje erwähnte, dass ein begrabenes reines virtuelles Wesen von ctor aufgerufen wurde, um einen Abbruch zu erzeugen. Ich habe ein Beispiel dafür neu erstellt. Wenn d hier konstruiert werden soll, ruft es zuerst seine Basisklasse A ctor auf und übergibt den inneren Zeiger an sich selbst. Der A ctor ruft eine reine virtuelle Methode auf, bevor die Tabelle mit einem gültigen Zeiger gefüllt wurde, da d noch nicht erstellt wurde.

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

kompilieren: g ++ -o aa aa.cpp

ulimit -c unbegrenzt

run: ./aa

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

Lassen Sie uns nun schnell die Kerndatei sehen und überprüfen, ob SIGABRT tatsächlich aufgerufen wurde:

gdb aa core

siehe regs:

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

Code überprüfen:

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

:) :)

Alexander Kruman
quelle
2

In meinem Fall lag dies an einer Eingabe in ein Array mit einem Index, der der Länge des Arrays entspricht.

string x[5];

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

    cin>>x[i];

}

Auf x [5] wird zugegriffen, was nicht vorhanden ist.

anonym
quelle
1

Wie "@sarnold" treffend hervorhebt, kann jeder Prozess ein Signal an einen anderen Prozess senden, daher kann ein Prozess SIGABORT an einen anderen Prozess senden, und in diesem Fall kann der empfangende Prozess nicht unterscheiden, ob er aufgrund seiner eigenen Optimierung von kommt Speicher usw., oder jemand anderes hat "unicastly", senden Sie an ihn.

In einem der Systeme, an denen ich gearbeitet habe, gibt es einen Deadlock-Detektor, der tatsächlich erkennt, ob ein Prozess aus einer Aufgabe herauskommt, indem er einen Herzschlag gibt oder nicht. Wenn nicht, wird der Prozess als Deadlock deklariert und SIGABORT an ihn gesendet.

Ich wollte diese Perspektive nur mit Bezug auf die gestellte Frage teilen.

Fooo
quelle
0

Ich werde meine Antwort aus der Perspektive einer wettbewerbsfähigen Programmierung (CP) geben , aber sie gilt auch für andere Bereiche.

Während der Arbeit mit cp sind die Einschränkungen oft recht groß.

Zum Beispiel : Ich hatte eine Frage mit N, M, Qsolchen Variablen , dass 1 ≤ N, M, Q < 10^5.

Der Fehler , den ich machte , war ich ein 2D - Integer - Array der Größe deklarierte 10000 x 10000in C++den und kämpfte SIGABRTFehlern bei Codechef für fast 2 Tage.

Nun, wenn wir rechnen:

Typische Größe einer Ganzzahl: 4 Bytes

Anzahl der Zellen in unserem Array: 10000 x 10000

Gesamtgröße (in Bytes): 400000000 Bytes = 4 * 10 ^ 8 ≈ 400 MB

Ihre Lösungen für solche Fragen funktionieren auf Ihrem PC (nicht immer), da er sich diese Größe leisten kann.

Die Ressourcen an Codierungsseiten (Online-Richtern) sind jedoch auf wenige KB beschränkt.

Daher der SIGABRTFehler und andere solche Fehler.

Fazit:

In solchen Fragen sollten wir kein Array oder Vektor oder einen anderen DS dieser Größe deklarieren, aber unsere Aufgabe ist es, unseren Algorithmus so effizient zu machen, dass er ohne sie (DS) oder mit weniger Speicher funktioniert.

PS : Es kann andere Gründe für diesen Fehler geben. oben war einer von ihnen.

Genius
quelle