2015-10-21 12 views
6

Questa domanda viene posta a mente di Linux. Viene utilizzato il compilatore GCC.Cosa succede se prendo SIGSEGV e il gestore del segnale causa un altro SIGSEGV?

Quale comportamento ci si può aspettare se SIGSEGV (intendo una violazione che normalmente causa SIGSEGV) si verifica all'interno di un gestore di segnali il cui scopo era catturare SIGSEGV? Esempio di codice per aiutare la discussione:

/* 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) */ 
} 

Immaginate, nel punto "Q", C'è un'istruzione macchina incriminato.

1) Senza il SA_RESETHAND | SA_NODEFER: Sembra che il sistema si trovi in ​​una trappola logica: in "Q", SIGSEGV deve essere generato. Ma SIGSEGV è bloccato nel gestore di segnale (comportamento di sigaction predefinito). Come può continuare l'esecuzione? Si congela? Supererà l'istruzione incriminata (credo di no)?

2) Con il SA_RESETHAND | SA_NODEFER: Credo che in questo caso il programma si arresti in modo "normale" quando SIGSEGV viene ripetuto.

3) con solo SA_NODEFER: suppongo che in questo caso il gestore di segnale venga chiamato in modo ricorsivo quando SIGSEGV viene ripetuto; se SIGSEGV viene sempre ripetuto, otteniamo un congelamento fino a quando lo stack non trabocca, e poi cosa.

+3

Quis custodiet ipsos custodes? –

+1

Si suppone che si chiamino solo le funzioni di rientro nei gestori di segnale. – edmz

+0

Cosa succede quando un proiettile perforante piercing un'armatura? – mah

risposta

3

Per impostazione predefinita, mentre il segnale viene gestito è mascherato, quindi non può essere attivato in modo ricorsivo. Se il segnale mascherato viene attivato da esecuzione del programma (accesso alla memoria non valida, segfault, divisione per 0, ecc), è definito il comportamento:

se SIGBUS, SIGFPE, SIGILL o SIGSEGV vengono generati mentre sono bloccate, il risultato non è definito, a meno che il segnale non sia stato generato da kill (2), sigqueue (3) o raise (3).

Sul mio sistema, provoca il crash del processo.

Con SA_NODEFER non c'è alcun mascheramento, quindi il segnale può essere gestito in modo ricorsivo fino allo straripamento dello stack. E l'aggiunta di SA_RESETHAND ripristinerebbe l'azione predefinita (arresto anomalo per SIGSEGV).

ho adattato il vostro esempio a semplice programma di test, in modo da poter verificare questo comportamento:

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