2012-06-08 6 views
14

Sto usando libjpeg adesso per salvare le immagini JPEG. Se c'è un errore, il comportamento predefinito di libjpeg è chiamare exit(), che voglio evitare poiché non è un errore fatale per il mio programma. libjpeg allows you to use your own error manager e impone che se si utilizza la propria funzione error_exit() (che chiama per impostazione predefinita exit()) deve restituire il controllo al chiamante a. libjpeg suggerisce di utilizzare setjmp.h per soddisfare questo requisito e non il programma exit().Lanciare un'eccezione in C++ in un callback C, possibilmente attraversando il limite della libreria dinamica ... è sicuro?

Tuttavia, sto scrivendo un programma C++ e ho accesso alle eccezioni. This question's answer afferma che è sicuro (come nel comportamento ben definito) generare un'eccezione dal callback. Ma non menziona le librerie dinamiche, e c'è una regola generale che non si generano eccezioni attraverso i confini delle librerie dinamiche.

Ecco un esempio:

#include <iostream> 
#include <jpeglib.h> 
#include <cstdio> 
#include <stdexcept> 

static void handleLibJpegFatalError(j_common_ptr cinfo) 
{ 
    (*cinfo->err->output_message)(cinfo); 
    throw std::runtime_error("error in libjpeg, check stderr"); 
} 

int main() 
{ 
    struct jpeg_compress_struct cinfo; 
    struct jpeg_error_mgr jerr; 
    FILE* file = std::fopen("out.jpeg", "wb"); // assume this doesn't fail for this example 

    try 
    { 
     cinfo.err = jpeg_std_error(&jerr); 
     jerr.error_exit = handleLibJpegFatalError; 

     // let's say this triggers a fatal error in libjpeg and handleLibJpegFatalError() is called 
     // by libjpeg 
     jpeg_create_compress(&cinfo); 
    } 
    catch (...) 
    { 
     std::cerr << "Error saving the JPEG!\n"; 
    } 

    jpeg_destroy_compress(&cinfo); 
    std::fclose(file); 
} 

Quello che vorrei sapere è: posso un'eccezione da questo richiamata, e prendere di nuovo nella mia richiesta, anche se libjpeg è compilato come una libreria dinamica ? libjpeg può essere una libreria statica o dinamica e, se si tratta di una libreria dinamica, potrebbe essere costruita con un compilatore diverso. Tuttavia, il codice che genera e intercetta l'eccezione si troverà sicuramente nella stessa unità di compilazione. Il codice sopra è sicuro?

FYI, sto sviluppando per OS X e Windows (e mantenendo il futuro di una possibilità Linux in mente), quindi sono più interessato a se questo è noto per essere un comportamento ben definito, in generale, e non per una piattaforma/compilatore specifica.

+0

Questo è perfettamente sicuro. Perché non dovrebbe essere? Le chiamate alle librerie condivise utilizzano ancora lo stesso stack di chiamate. –

+1

Questo potrebbe essere correlato: http: // stackoverflow.it/questions/10318363/is-it-safe-per-xs-error-handler-to-exceptions – Pubby

+1

@nw: Non riesco a pensare al motivo per cui non sarebbe stato salvato; Voglio solo assicurarmi che nulla venga spazzato via quando si svolge lo stack. Potrebbe essere perfettamente sicuro, ma sono stato morso nel culo assumendo le cose in passato, quindi sto giocando al sicuro qui e il doppio controllo. – Cornstalks

risposta

4

Non è sicuro. A seconda di come è stato compilato il codice della libreria non C++, le tabelle di svolgimento necessarie potrebbero non esistere. Questo è solo un pratico motivo per cui potrebbe fallire; la ragione concettuale è che è semplicemente un comportamento indefinito.

Si dovrebbe seguire la documentazione e utilizzare setjmp/longjmp per ottenere appena fuori la chiamata a libjpeg codice, quindi un'eccezione immediatamente nel corpo if (setjmp(...)) { ... } se si desidera utilizzare le eccezioni.

+0

Stai parlando di srotolare i frame all'interno della catena di chiamata della libreria? Anche quelli non verranno svelati con 'setjmp'. Il codice C dovrebbe sovrascrivere specificamente il frame SEH/.eh_frame/etc per rovinare lo srotolamento delle chiamate C++, cosa che non accadrebbe a meno che qualcuno non stesse intenzionalmente tentando di rovinare tutto. –

+0

Non è sicuro lanciare un'eccezione in una richiamata a meno che non venga gestita anche nella richiamata. Per quanto riguarda dove/come può fallire, se il codice della libreria C non ha affatto le informazioni di unwind (no '.eh_frame') e non usa i puntatori di frame, non c'è assolutamente modo di retrocedere oltre il codice C e dare un senso a il precedente callframe in cui si suppone che l'eccezione sia gestita. –

4

L'altra risposta vale qui. Nulla verrà spazzato via quando si srotola lo stack. Non importa nemmeno se la libreria utilizza internamente alcune regole di chiamata pazzesche, purché non interferisca in modo specifico con le strutture di gestione delle eccezioni dell'implementazione C++ (che non è un programma C). Nessuna implementazione C++ che conosca trova il blocco catch facendo scattare i frame dello stack (che renderebbe l'ottimizzazione un incubo), tutti mantengono strutture interne per la gestione delle eccezioni. Finché una chiamata nella parte inferiore della catena di chiamate non interferisce con tali strutture, lo sbobinamento dello stack funzionerà perfettamente per tutto il codice personale. Ora, in generale, è abbastanza probabile che questo lascerebbe una libreria con uno stato interno incasinato perché non si restituisce mai l'esecuzione alla libreria per la pulizia, ma nel caso della richiamata di errore, libjpeg si aspetta che il flusso di controllo non ritorni e presumibilmente già ripulito da se stesso.

In questo caso, ci andrei. In generale, vorrei solo lanciare eccezioni fatali da un callback in C.

Spero che questo abbia aiutato.

Problemi correlati