Der Segmentierungsfehler selbst hängt

Lesezeit: 4 Minuten

Benutzer-Avatar
xeor

Ich hatte heute einige Probleme mit einem Server und ich habe es jetzt darauf reduziert, dass er nicht in der Lage ist, Prozesse loszuwerden, die einen Segfault bekommen.

Nachdem der Prozess einen Seg-Fault erhält, bleibt der Prozess einfach hängen und wird nicht beendet.

Ein Test das sollte den Fehler verursachen Segmentation fault (core dumped).

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
 char *buf;
 buf = malloc(1<<31);
 fgets(buf, 1024, stdin);
 printf("%s\n", buf);
 return 1;
}

Kompilieren und Berechtigungen setzen mit gcc segfault.c -o segfault && chmod +x segfault.

Wenn Sie dies ausführen (und 1 Mal die Eingabetaste drücken), bleibt der problematische Server hängen. Ich habe dies auch auf einem anderen Server mit derselben Kernel-Version (und den meisten derselben Pakete) ausgeführt, und es wird der Seg-Fehler angezeigt und dann beendet.

Hier sind die letzten Zeilen nach dem Laufen strace ./segfault auf beiden Servern.

Schlechter Server

"\n", 1024)                     = 1
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0} ---
# It hangs here....

Arbeitsserver

"\n", 1024)                     = 1
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
[email protected] { ~ }# echo $?
139

Wenn der Prozess hängt (nach einem Segfault), sieht es so aus.

Kann es nicht ^c

[email protected] { ~ }# ./segfault

^C^C^C

Eintrag von ps aux

root 22944 0.0 0.0 69700 444 pts/18 S+ 15:39 0:00 ./segfault

cat /proc/22944/stack

[<ffffffff81223ca8>] do_coredump+0x978/0xb10
[<ffffffff810850c7>] get_signal_to_deliver+0x1c7/0x6d0
[<ffffffff81013407>] do_signal+0x57/0x6c0
[<ffffffff81013ad9>] do_notify_resume+0x69/0xb0
[<ffffffff8160bbfc>] retint_signal+0x48/0x8c
[<ffffffffffffffff>] 0xffffffffffffffff

Eine andere lustige Sache ist, dass ich nicht anhängen kann strace zu einem hängenden Segfault-Prozess. Dadurch wird es tatsächlich getötet.

[email protected] { ~ }# strace -p 1234
Process 1234 attached
+++ killed by SIGSEGV (core dumped) +++

ulimit -c 0 ist gesessen und ulimit -c, ulimit -H -cund ulimit -S -c alles zeigt den Wert 0

  • Kernelversion: 3.10.0-229.14.1.el7.x86_64
  • Distro-Version: Red Hat Enterprise Linux Server release 7.1 (Maipo)
  • Läuft in vmware

Der Server funktioniert wie er sollte auf alles andere.

Aktualisieren
Herunterfahren abrt (systemctl stop abrtd.service) behebt das Problem mit Prozessen, die bereits nach dem Core-Dump hängen geblieben sind, und neuen Prozessen, die Core-Dump ausführen. Ein erneuter Start brachte das Problem nicht zurück.

Aktualisierung 2016-01-26
Wir haben ein Problem, das ähnlich aussah, aber nicht ganz gleich war. Der anfängliche Code, der zum Testen verwendet wurde:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
 char *buf;
 buf = malloc(1<<31);
 fgets(buf, 1024, stdin);
 printf("%s\n", buf);
 return 1;
}

hing. Die Ausgabe von cat /proc/<pid>/maps war

00400000-00401000 r-xp 00000000 fd:00 13143328                           /root/segfault
00600000-00601000 r--p 00000000 fd:00 13143328                           /root/segfault
00601000-00602000 rw-p 00001000 fd:00 13143328                           /root/segfault
7f6c08000000-7f6c08021000 rw-p 00000000 00:00 0
7f6c08021000-7f6c0c000000 ---p 00000000 00:00 0
7f6c0fd5b000-7f6c0ff11000 r-xp 00000000 fd:00 14284                      /usr/lib64/libc-2.17.so
7f6c0ff11000-7f6c10111000 ---p 001b6000 fd:00 14284                      /usr/lib64/libc-2.17.so
7f6c10111000-7f6c10115000 r--p 001b6000 fd:00 14284                      /usr/lib64/libc-2.17.so
7f6c10115000-7f6c10117000 rw-p 001ba000 fd:00 14284                      /usr/lib64/libc-2.17.so
7f6c10117000-7f6c1011c000 rw-p 00000000 00:00 0
7f6c1011c000-7f6c1013d000 r-xp 00000000 fd:00 14274                      /usr/lib64/ld-2.17.so
7f6c10330000-7f6c10333000 rw-p 00000000 00:00 0
7f6c1033b000-7f6c1033d000 rw-p 00000000 00:00 0
7f6c1033d000-7f6c1033e000 r--p 00021000 fd:00 14274                      /usr/lib64/ld-2.17.so
7f6c1033e000-7f6c1033f000 rw-p 00022000 fd:00 14274                      /usr/lib64/ld-2.17.so
7f6c1033f000-7f6c10340000 rw-p 00000000 00:00 0
7ffc13b5b000-7ffc13b7c000 rw-p 00000000 00:00 0                          [stack]
7ffc13bad000-7ffc13baf000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

Der kleinere C-Code (int main(void){*(volatile char*)0=0;}), um einen Segfault auszulösen, hat einen Segfault verursacht und ist nicht hängen geblieben …

  • Überprüfen Sie den Rückgabewert von malloc. 100% sicher, dass es NULL ist. Aber malloc(1<<31); kann tatsächlich funktionieren, wenn >2 GB freier Speicher verfügbar sind.

    – Jabberwocky

    12. November 2015 um 14:20 Uhr


  • @Michael Walz: Das ist die Idee. Es soll einen Segfault verursachen.

    – Jordan Melo

    12. November 2015 um 14:24 Uhr

  • @JordanMelo, aber ich denke es kann Arbeit. Wenn Sie sicher sein wollen, dass Sie einen Segfault erhalten, ist es besser, einen NULL-Zeiger zu dereferenzieren. Dies wird die ganze Zeit segfault.

    – Jabberwocky

    12. November 2015 um 14:25 Uhr


  • Klingt so, als ob die Maschine beim Erstellen des Core-Dump hängen bleibt (oder nur sehr lange dauert). Wenn Sie Core-Dumps deaktivieren (ulimit -c 0 auf bash), ändert sich etwas?

    – Nate Eldredge

    12. November 2015 um 15:02 Uhr

  • Möglicherweise läuft der abrtd-Daemon. Es sammelt Core-Dumps und meldet sie. Stoppen Sie es und deaktivieren Sie es.

    – meuh

    12. November 2015 um 15:17 Uhr

WARNUNG – Diese Antwort enthält eine Reihe von Vermutungen, die auf den vorliegenden unvollständigen Informationen beruhen. Hoffentlich ist es trotzdem nützlich!

Warum scheint der Segfault zu hängen?

Wie der Stack-Trace zeigt, ist der Kernel damit beschäftigt, einen Core-Dump des abgestürzten Prozesses zu erstellen.

Aber warum dauert das so lange? Eine wahrscheinliche Erklärung ist, dass die Methode, die Sie zum Erstellen der Segfaults verwenden, dazu führt, dass der Prozess einen riesigen virtuellen Adressraum hat.

Wie in den Kommentaren von MM ausgeführt, ist das Ergebnis des Ausdrucks 1<<31 durch die C-Standards nicht definiert, daher ist es schwierig zu sagen, welcher tatsächliche Wert an malloc übergeben wird, aber basierend auf dem nachfolgenden Verhalten gehe ich davon aus ist eine große Zahl.

Beachten Sie, dass Sie für den Erfolg von malloc nicht unbedingt so viel RAM in Ihrem System haben müssen – der Kernel wird die virtuelle Größe Ihres Prozesses erweitern, aber tatsächlicher RAM wird nur zugewiesen, wenn Ihr Programm tatsächlich auf diesen RAM zugreift.

Ich glaube, dass der Aufruf von malloc erfolgreich ist oder zumindest zurückkehrt, weil Sie angeben, dass es segfaults gibt, nachdem Sie die Eingabetaste gedrückt haben, also nach dem Aufruf von fgets.

In jedem Fall führt der Segfault dazu, dass der Kernel einen Core-Dump durchführt. Wenn der Prozess eine große virtuelle Größe hat, kann dies lange dauern, insbesondere wenn der Kernel beschließt, alle Seiten auszugeben, auch diejenigen, die noch nie vom Prozess berührt wurden. Ich bin mir nicht sicher, ob dies der Fall ist, aber wenn dies der Fall wäre und nicht genügend RAM im System vorhanden wäre, müsste es damit beginnen, Seiten in den und aus dem Speicher zu verschieben, um sie in den Core-Dump zu kopieren. Dies würde eine hohe E/A-Last erzeugen, die dazu führen könnte, dass der Prozess scheinbar nicht mehr reagiert (und die Systemleistung insgesamt beeinträchtigt würde).

Möglicherweise können Sie einiges davon überprüfen, indem Sie im abrtd-Dump-Verzeichnis nachsehen (möglicherweise /var/tmp/abrtoder prüfen /etc/abrt/abrt.conf), wo Sie die Core-Dumps (oder vielleicht partielle Core-Dumps) finden können, die erstellt wurden.

Wenn Sie das Verhalten reproduzieren können, können Sie Folgendes überprüfen:

  • /proc/[pid]/maps um die Adressraumkarte des Prozesses zu sehen und zu sehen, ob sie wirklich groß ist
  • Verwenden Sie ein Tool wie vmstat, um zu sehen, ob das System auslagert, wie viele E/A-Vorgänge stattfinden und wie viele E/A-Wartezustände auftreten
  • Wenn du hättest sar Wenn Sie dann ausgeführt werden, können Sie möglicherweise ähnliche Informationen auch für den Zeitraum vor dem Neustart von abrtd sehen.

Warum wird ein Core-Dump erstellt, obwohl ulimit -c 0 ist?

Entsprechend dieser Fehlerberichtlöst abrtd unabhängig von den ulimit-Einstellungen die Erfassung eines Core-Dumps aus.

Warum trat dies nicht erneut auf, als arbtd erneut gestartet wurde?

Dafür gibt es ein paar mögliche Erklärungen. Zum einen würde es von der Menge an freiem RAM im System abhängen. Es kann sein, dass ein einzelner Core-Dump eines großen Prozesses nicht so lange dauert und nicht als hängend wahrgenommen wird, wenn genügend freier RAM vorhanden ist und das System nicht zum Austauschen gedrängt wird.

Wenn Sie in Ihren anfänglichen Experimenten mehrere Prozesse in diesem Zustand hatten, dann wären die Symptome viel schlimmer, als wenn Sie nur einen einzigen Prozess dazu bringen, sich falsch zu verhalten.

Eine andere Möglichkeit besteht darin, dass die Konfiguration von abrtd geändert, der Dienst jedoch noch nicht neu geladen wurde, sodass er beim Neustart die neue Konfiguration verwendet und möglicherweise sein Verhalten geändert hat.

Es ist auch möglich, dass ein yum-Update abrtd aktualisiert, aber nicht neu gestartet hat, sodass beim Neustart die neue Version ausgeführt wurde.

  • Danke für eine gute Antwort. Das lsusb -t Das Programm verursachte ebenfalls einen Segfault und hatte das gleiche Verhalten (auch das winzige .c-Snippet in den Kommentaren). Es hing tagelang, bis es getötet wurde. Es wurden keine Konfigurationsänderungen an den Abrt-Dateien vorgenommen, das habe ich jetzt überprüft. Ich werde Ihre Vorschläge überprüfen, wenn dies erneut vorkommt. Dieser Fehlerbericht sieht alt aus. Ziemlich sicher, dass das hier nicht Teil des Problems ist..

    – xeor

    16. November 2015 um 11:02 Uhr

1095790cookie-checkDer Segmentierungsfehler selbst hängt

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy