PDA

Visualizza la versione completa : [c/c++]Catturare l'errore di segmentation fault


anx721
17-04-2004, 16:55
Salve, sapete se c'è un modo per catturare l'errore di segmentation fault da programma e riuscire ad esempio a trasformarlo in un'eccezione?

Michele Facchin
17-04-2004, 17:08
Magari esistesse :D, devi fare i controlli tu programmatore. :quipy:

anx721
17-04-2004, 17:19
Mi spiego meglio. Supponiamo che io voglia usare nel mio programma una funzione funz() scritta da qualcuno. Ad ogni modo non posso avere la certezza che questa funzione funz() sia stata scritta bene e che non causera il suddetto errore provocando l'uscita dal mio programma. Allora vorrei ad esempio invocare la funzione funz() all'interno di un costrutto come try/catch (uso la terminologia java) che catturi l'errore, nel senso che l'errore provoca l'uscita dalla funzione che l'ha causato, ma non dal programma, permettendomi di gestire la cosa. In genere le eccezioni funzionano cosi, nel senso che se nessuno si preoccupa di "acchiapparle" possono farti uscire dal programma, ma se le catturri il programma non termina.

:ciauz:

Michele Facchin
17-04-2004, 17:21
Non sò se esista anche nel C/C++.
Io pensò di nò, perchè sennò non ci sarebbero tanti problemi di sicurezza legati al buffer overflow e robe varie.

Non sò dirti se esiste questa cosa del java anche nel C, penso di nò cmq.

Ciao

internet
17-04-2004, 17:49
una possibile soluzione in C



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

static jmp_buf env;

void bad()
{
char* a = (char*)0xa0000;

printf("inside bad()\n");

*(a) = 100;
}

/* funzione che gestisce i segnali da catturare */
void sighand(int signo)
{
if (signo == SIGSEGV)
printf("SIGSEGV captured & handled\n");

/* salta nella riga in blu e fa in modo che setjmp() restituisca 1 */
longjmp(env, 1);
}

int main(void)
{
signal(SIGSEGV, sighand); /* abilita la cattura del segnale SEGMENTATION FAULT */

/* la prma volta setjmp() restituisce 0 */
if (setjmp(env) == 0)
{
bad();
printf("bad() test passed!\n");
}
else
printf("very bad() function!\n");

return 0;
}


in C++ la stessa cosa si può fare con la gestione mediante blocchi try catch.

anx721
17-04-2004, 18:48
Grazie internet,

potresti spiegarmi meglio il funzionamento della cosa o indicarmi un riferimento in leggere qlcosa?

Cosa fa l'istruzione

setjmp(env)?

perche longjmp(env, 1) provoca il salto alla riga blue?

Mi potresti dire come si puo fare in c++ con i try e catch?

Grazie,

:ciauz:

internet
17-04-2004, 21:14
Il programma fa in modo che venga catturato il segnale di segmentation fault (SIGSEGV), e quando si presenta lo gestisce con sighand() che praticamente, tramite longjmp(), salta l'esecuzione alla riga in blu, ma questa volta la funzione setjmp() non restituisce 0, ma 1 come indicato da longjmp(), per cui il programma stamperà "very bad() function!".

Se nella funzione bad() commenti l'ultima assegnazione, non ci sarà un segnale di SIGSEGV, la funzione sighand() non verrà invocata, il programma stampa "bad() test passed!" e terminerà normalmente.

La signal() serve per definire il comportamento del processo in seguito alla ricezione di un segnale, è possibile registrare una propria funzione per gestire uno o più segnali.

un pdf in italiano sui segnali (601 KB zippati, clicca sul destro e salva oggetto con nome)
http://utenti.lycos.it/diabdiary/08%20System%20Calls%20-%20Segnali.zip

setjmp() salva lo stato corrente (stack pointer, program counter, + altri registri della CPU) nel parametro fornito come argomento, e la prima volta che viene invocato restituisce 0, serve essenzialemente a definire un punto di ritorno simile al try/catch usato da linguaggi come java, C++.

longjmp() è "paragonabile" al throw dei linguaggi java, c++
ha l'effetto di saltare direttamente nel punto in cui è definito nel parametro env (grazie al program counter contenuto in esso) questa operazione si chiama stack unwinding (http://www.google.com/search?q=%22stack+unwinding%22)

un link per approfondire su setjmp()/longjmp()
http://www.csl.mtu.edu/cs4411.ck/www/NOTES/non-local-goto/

Per quanto riguarda l'accoppiata try/catch del C++ e signal() ci sono problemi e non sono riuscito a risolverlo, in pratica nella signal mettendo un throw genera un segnale di abort.

Sul libro "The C++ programming language" (scritto dall'autore del C++) leggo ora che
"The C-style stack unwinding (using setjmp and longjmp) is incompatible with exception handling and is best avoided. C-style stack unwinding and signals are not discussed in this book, so the reference presented are to the ISO C++ standard"

quindi potrebbe funzionare in alcuni SO e in altri no.

anx721
17-04-2004, 23:49
Grazie per i link che mi hai dato

quindi per poter gestire un sengale come il segmentation fault, se voglio che il programma continui, devo comunque definire un punto di ripristino a cui saltare con un'istuzione longjmp, giusto? Ho provato infatti ad eleiminare l'istruzione di salto longjmp alla fine della funzione handler e provoca un errore nel programma.

Ad ogni modo, mi sembra di capire che quando si genera un segmentation fault possono gia essere avvenuti dei danni alla memoria per cui bisognerebbe limirtarsi a fare il minimo per gstire l'errore e terminare il programma.

internet
18-04-2004, 00:08
Originariamente inviato da anx721
Grazie per i link che mi hai dato

quindi per poter gestire un sengale come il segmentation fault, se voglio che il programma continui, devo comunque definire un punto di ripristino a cui saltare con un'istuzione longjmp, giusto?

Si è così.


Ad ogni modo, mi sembra di capire che quando si genera un segmentation fault possono gia essere avvenuti dei danni alla memoria per cui bisognerebbe limirtarsi a fare il minimo per gstire l'errore e terminare il programma.

In effetti la signal è più utile per altri tipi di segnali ad esempio CTRL-C per terminare un programma, che genera un SIGINT, quasi tutti i server lo catturano per terminare correttamente le connessioni in corso, e i DBMS per gestire in modo corretto i log per le transazioni.

Una nota
La funzione bad() nel momento in cui esegue quella modifica finale, non avendone i diritti, non crea casini perchè gira nello spazio utente, cosa diversa se fosse un driver che gira nello spazio del kernel, causerebbe un BSOD o un panic a seconda dei SO.

Di solito comunque sui sistemi *nix si preferisce analizzare i core files generati, su Win invece è conveniente catturare il segnale SIGSEGV e salvaro lo stack trace, i registri e altre strutture utili per il debug.

Loading