2013-06-05 7 views
12

Ho una funzione particolare (un gestore di segnale) per il quale mi piacerebbe rilevare la ricorsione, cioè per capire se la funzione si è chiamata direttamente o indirettamente. La cosa complicata è che la funzione chiama un codice non sotto il suo controllo in un punto e quel codice potrebbe fare qualsiasi cosa.Rileva la ricorsione in modo affidabile anche in presenza di salti non locali

Normalmente, avevo appena scrivere qualcosa di simile

void foo() { 
    static int recursed = 0; 
    if(recursed) { 
     ... 
    } 
    recursed = 1; 
    othercode(); 
    recursed = 0; 
} 

ma in questo caso, io sono preoccupato del fatto che othercode potrebbe utilizzare un longjmp o simili a scoppiare, con conseguente recursed rimanendo a 1. Nel evento che la mia funzione è saltata fuori in questo modo, voglio assicurarmi che non veda se stesso come ricorsivo se viene chiamato più tardi (il fatto che sia longjmp 'd out non è un problema altrimenti).

Nota: ritengo che sia probabile che sia longjmp. Il othercode è un gestore di segnali concatenati da un altro codice in-the-wild e esistono gestori per es. SIGSEGV che usano longjmp per ripristinare il contesto (ad esempio come gestori di eccezioni "protezione da errore"). Si noti che l'utilizzo di longjmp in un gestore di segnale sincrono è generalmente sicuro. In ogni caso, non mi interessa particolarmente se l'altro codice è sicuro, perché non è qualcosa sotto il mio controllo.

+0

Siete preoccupati che 'longjmp' sia probabile, o solo che sia una possibilità? – Patashu

+0

@Patashu: probabile. Vedi la mia modifica. – nneonneo

+0

Il titolo della domanda deve essere modificato per essere un po 'più specifico, qualcosa come' Rileva re-entrancy anche quando longjmp è usato ' – Patashu

risposta

3

Non sono sicuro di quale sarebbe esattamente il codice per farlo, ma invece di un int statico, potresti avere un vuoto statico *. Invece di impostarlo su 1, impostarlo in modo che punti al frame dello stack corrente. Oltre a verificare se è diverso da zero, si controlla per assicurarsi che l'indirizzo di ritorno dal successivo stack frame dopo recursed punti in realtà a una posizione nel codice di foo, e anche che recursed è sopra il puntatore stack corrente, vale a dire non spuntato.

Suoni molto fragili e dipendenti dall'architettura.

+0

O forse è più semplice osservare l'indirizzo di ritorno dai punti del frame stack di foo subito dopo che l'istruzione di una chiamata è andata a vuoto, ma che * sicuramente * non sarebbe stato portabile. – morningstar

+0

Ho considerato questo. Funziona molto bene, tranne che per un minuscolo caso d'angolo: supponiamo che 'othercode' salti su una funzione ben al di sopra di' foo', che chiama qualche altra funzione che alloca (ma non usa completamente) un buffer di stack gigante, quindi finisce innescando 'foo'. Se sono sfortunato, il gigantesco stack buffer sposta entrambi il puntatore dello stack sotto 'pippo' e conserva lo stack' foo' originale, rendendolo simile a una ricorsione. – nneonneo

+0

Naturalmente, questo è piuttosto improbabile, motivo per cui probabilmente finirò per utilizzare questa soluzione.Ma preferirei trovare una soluzione che non abbia questo problema. – nneonneo

0

In base allo standard POSIX per signal(7), longjmp() non è una delle chiamate che è possibile chiamare dall'interno di un gestore di segnale. Prima ancora di pensare a questo problema, la documentazione longjmp(3) dice che devi assicurarti che il codice che stai chiamando usi sigsetjmp() e siglongjmp()

Se il codice che stai chiamando sta saltando fuori dal gestore del segnale, allora io Puoi vedere come puoi sapere quando aggiornare la tua variabile recursed, a meno che tu non controlli anche una funzione di callback che questo codice sconosciuto richiama nell'applicazione.

+0

Questi si applicano solo ai ** segnali asincroni **. Sto scrivendo un gestore di segnale per 'SIGSEGV' e altri segnali normalmente sincroni, quindi non dovrebbe essere un problema. – nneonneo

Problemi correlati