Wrapper di eccezione per l'app Carbon C in OSX
-
03-07-2019 - |
Domanda
Come posso rilevare e gestire in modo efficiente i guasti di segmentazione da C in un'applicazione OSX Carbon?
Background: sto realizzando un'applicazione OSX Carbon. Devo chiamare una funzione di libreria da una terza parte. A causa di problemi di threading, la funzione può occasionalmente arrestarsi in modo anomalo, di solito perché si sta aggiornando da un thread e ha un puntatore o un handle internamente non aggiornati mentre lo interrogo da un altro. La funzione è una scatola nera per me. Voglio poter chiamare la funzione ma essere in grado di "catturare" se si è bloccato e fornire un ritorno alternativo. In Windows, posso usare il semplice compilatore Visual C e Intel C __try {} e __except.
/* Working Windows Example */
__try { x=DangerousFunction(y);}
__except(EXCEPTION_EXECUTE_HANDLER) {x=0.0;} /* whups, func crashed! */
Sto cercando di creare lo stesso tipo di crash-catcher per OSX. Sto usando C puro su un'applicazione molto grande. Chiamo la funzione milioni di volte al secondo, quindi anche l'efficienza è molto importante. (Sorprendentemente, l'overhead di Windows __try () è incredibilmente piccolo!)
Ecco cosa ho sperimentato:
1) Eccezioni C ++. Non sono sicuro che le eccezioni C ++ catturino gli arresti anomali. E la mia app è attualmente C. Potrei provare wrapper e #ifdefs per renderlo C ++ ma questo è molto lavoro per l'app, e non credo che le eccezioni C ++ colpiranno il crash.
2) segnale + setjump + longjmp. Ho pensato che avrebbe funzionato ... è quello per cui è stato progettato. Ma ho impostato il mio gestore degli errori SEGV [in effetti l'ho impostato per ogni segnale!] E non viene mai chiamato durante l'incidente. Posso testare manualmente (e riuscire) quando si chiama rilancio (SEGV). Ma i crash non sembrano in realtà chiamarlo. Ritengo che le applicazioni CFM NON abbiano accesso a tutti i segnali BSD, solo un sottoinsieme e che le applicazioni Mach siano necessarie per la cosa reale.
3) MPSetExceptionHandler. Non ben documentato. Ho tentato di impostare un gestore. Si è compilato e funzionato, ma non ha catturato il segfault.
Soluzione
Sei sicuro di non avere un SIGBUS piuttosto che un SIGSEGV?
Il seguito cattura SIGBUS come causato dal tentativo di scrivere nella posizione di memoria 0:
cristi:tmp diciu$ cat test.c
#include <signal.h>
static void sigac(int sig)
{
printf("sig action here, signal is %d\n", sig);
exit(1);
}
int main()
{
(void)signal(SIGSEGV, sigac);
(void)signal(SIGBUS, sigac);
printf("Raising\n");
strcpy(0, "aaksdjkajskd|");
}
cristi:tmp diciu$ ./a.out
Raising
sig action here, signal is 10