2015-10-21 6 views
6

Diese Frage wird unter Linux gestellt. GCC-Compiler wird verwendet.Was passiert, wenn ich SIGSEGV abfange und der Signalhandler einen anderen SIGSEGV verursacht?

Welches Verhalten kann erwartet werden, wenn SIGSEGV (ich meine eine Verletzung, die normalerweise SIGSEGV verursacht) innerhalb eines Signalhandlers auftritt, dessen Zweck es war, SIGSEGV zu fangen? Codebeispiel wird die Diskussion zu unterstützen:

/* In main or whatever */ 
{ 
    struct sigaction sa = {}; /* initialised to all zero (I vote for GCC style breach of standard here) */ 
    sa.sa_handler = DisasterSignals; 
    sa.sa_flags = SA_RESETHAND | SA_NODEFER; /* To have or have not */ 
    sigaction(SIGSEGV, &sa, NULL); 
} 

static void DisasterSignals(int signal) 
{ 
    /* We cannot save the situation, the purpose of catching the signal is 
    only to do something clever to aid debugging before we go. */ 

    /* Q: What if we segfault in here?? */ 

    abort(); /* This should give us the expected core dump (if we survive to this point) */ 
} 

Stellen Sie sich vor, in dem Punkt „Q“, gibt es einen säumigen Maschinenbefehl.

1) Ohne die SA_RESETHAND | SA_NODEFER: Dies scheint das System in eine logische Falle zu setzen: Bei "Q" sollte SIGSEGV generiert werden. Aber SIGSEGV ist im Signalhandler blockiert (Standard-sigaction-Verhalten). Wie kann die Ausführung fortgesetzt werden? Wird es einfrieren? Wird es an der beleidigenden Anweisung vorbeikommen (ich denke nicht)?

2) Mit der SA_RESETHAND | SA_NODEFER: Ich denke, in diesem Fall wird das Programm auf eine "normale" Art und Weise abstürzen, wenn SIGSEGV wiederholt wird.

3) Mit nur SA_NODEFER: Ich denke, in diesem Fall wird der Signalhandler rekursiv aufgerufen, wenn SIGSEGV wiederholt wird; Wenn der SIGSEGV immer wiederholt wird, erhalten wir ein Einfrieren, bis der Stapel überläuft, und was dann.

+3

Quis custodiet ipsos custodes? –

+1

Sie sollten nur Wiedereintrittsfunktionen in Signalhandlern aufrufen. – edmz

+0

Was passiert, wenn eine panzerbrechende Kugel die Panzerung durchbohrt? – mah

Antwort

3

Standardmäßig wird das Signal während der Verarbeitung maskiert, sodass es nicht rekursiv ausgelöst werden kann. Wenn maskiertes Signal, das durch die Programmausführung (ungültigen Speicherzugriff, segfault, Division durch 0 etc.) ausgelöst wird, ist das Verhalten nicht definiert:

Wenn SIGBUS, SIGFPE, SIGILL oder SIGSEGV erzeugt werden, während sie blockiert sind, Das Ergebnis ist nicht definiert, es sei denn, das Signal wurde durch kill (2), sigqueue (3) oder raise (3) generiert.

Auf meinem System verursacht es einen Absturz des Prozesses.

Mit SA_NODEFER gibt es keine Maskierung, daher kann das Signal rekursiv behandelt werden, bis der Stack überläuft. Und das Hinzufügen von SA_RESETHAND würde Standardaktion wiederherstellen (Absturz für SIGSEGV).

ich dein Beispiel auf einfache Testprogramm angepasst, so dass Sie dieses Verhalten überprüfen können:

#include<signal.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<unistd.h> 

volatile char *ptr; 

static void DisasterSignals(int signal) 
{ 
    /* We cannot save the situation, the purpose of catching the signal is 
    only to do something clever to aid debugging before we go. */ 
    write(1, "11\n", 3); 
    *ptr = 1; 
    write(1, "13\n", 3); 
    abort(); /* This should give us the expected core dump (if we survive to this point) */ 
} 

struct sigaction sa = {}; /* initialised to all zero (I vote for GCC style breach of standard here) */ 

int main() 
{ 
    sa.sa_handler = DisasterSignals; 
    sa.sa_flags = /*SA_RESETHAND | */SA_NODEFER; /* To have or have not */ 
    sigaction(SIGSEGV, &sa, NULL); 

    write(1, "25\n", 3); 
    *ptr = 1; 
} 
Verwandte Themen