2013-05-28 11 views
8

Sia console node e di QT5 V8-based QJSEngine può essere precipitato dal codice seguente: uscitaCome gestire crash del motore V8 quando processo esaurisce la memoria

a = []; for (;;) { a.push("hello"); } 

del nodo prima di schianto:

FATAL ERROR: JS Allocation failed - process out of memory 
uscita

QJSEngine 's prima schianto:

# 
# Fatal error in JS 
# Allocation failed - process out of memory 
# 

Se Corro la mia app di test QJSEngine (vedi sotto) sotto un debugger, mostra una chiamata v8::internal::OS::DebugBreak all'interno del codice V8. Se avvolgo il codice chiamando QJSEngine::evaluate in __try-__except (SEH), l'app non si arresta in modo anomalo, ma questa soluzione è specifica per Windows.

Domanda: Esiste un modo per gestire v8::internal::OS::DebugBreak in un modo indipendente dalla piattaforma in applicazioni nodi e Qt?

=== === codice di prova QJSEngine

Ambiente di sviluppo: QtCreator con QT5 e Windows SDK 7.1, su Windows XP SP3

QJSEngineTest.pro:

TEMPLATE = app 
QT -= gui 
QT += core qml 
CONFIG -= app_bundle 
CONFIG += console 
SOURCES += main.cpp 
TARGET = QJSEngineTest 

principale .cpp senza SEH (questo si bloccherà):

#include <QtQml/QJSEngine> 

int main(int, char**) 
{ 
    try { 
    QJSEngine engine; 
    QJSValue value = engine.evaluate("a = []; for (;;) { a.push('hello'); }"); 
    qDebug(value.isError() ? "Error" : value.toString().toStdString().c_str()); 
    } catch (...) { 
    qDebug("Exception"); 
    } 
    return 0; 
} 

main.cpp con SEH (questo non collasserà, uscite "eccezione irreversibile"):

#include <QtQml/QJSEngine> 
#include <Windows.h> 

void runTest() 
{ 
    try { 
    QJSEngine engine; 
    QJSValue value = engine.evaluate("a = []; for (;;) { a.push('hello'); }"); 
    qDebug(value.isError() ? "Error" : value.toString().toStdString().c_str()); 
    } catch (...) { 
    qDebug("Exception"); 
    } 
} 

int main(int, char**) 
{ 
    __try { 
    runTest(); 
    } __except(EXCEPTION_EXECUTE_HANDLER) { 
    qDebug("Fatal exception"); 
    } 
    return 0; 
} 

risposta

3

Non credo ci sia un modo cross-platform per intrappolare V8 errori fatali, ma anche se ci fosse, o se ci fosse un modo per intrappolarli su tutte le piattaforme a cui tieni, non sono sicuro di cosa ti avrebbe comprato.

Il problema è che V8 utilizza uno global flag che registra se si è verificato un errore irreversibile. Una volta impostato questo flag, V8 rifiuterà qualsiasi tentativo di creare nuovi contesti JavaScript, quindi non ha senso continuare in ogni caso. Prova a eseguire qualche codice JavaScript benigno dopo aver rilevato l'errore fatale iniziale. Se ho ragione, avrai subito un altro errore fatale.

A mio parere, la cosa giusta sarebbe che Node e Qt configurino il V8 in modo da non generare errori fatali. Ora che V8 supporta gli isolati e i vincoli di memoria, gli errori fatali che uccidono i processi non sono più appropriati. Sfortunatamente sembra che il codice di gestione degli errori di V8 non supporti ancora pienamente quelle nuove funzionalità, e funziona ancora con l'assunto che le condizioni di esaurimento della memoria siano sempre irrecuperabili.

+0

Si noti inoltre che è possibile registrare una richiamata prima di interrompere utilizzando V8 :: SetFatalErrorHandler(), sebbene questo non permetta di rilassarsi lo stack v8. Puoi anche controllare OS :: Abort() con --no-hard_abort per far uscire il processo in modo silenzioso (SIGABRT) piuttosto che con una violazione di accesso (V8_IMMEDIATE_CRASH()). (Non sono sicuro in quali circostanze viene richiamato DebugBreak() - può essere solo quando è collegato un debugger.) –

Problemi correlati