node控制台和Qt5的基于V8的QJSEngine
都可以通过以下代码崩溃:
a = []; for (;;) { a.push("hello"); }
崩溃前节点的输出:
FATAL ERROR: JS Allocation failed - process out of memory
崩溃前 QJSEngine
的输出:
#
# Fatal error in JS
# Allocation failed - process out of memory
#
如果我在调试器下运行我的QJSEngine
测试应用程序(见下文),它会在V8代码中显示v8::internal::OS::DebugBreak
调用。如果我将调用QJSEngine::evaluate
的代码包装到__try-__except
(SEH)中,那么应用程序不会崩溃,但此解决方案是特定于Windows的。
问题:有没有办法在节点和Qt应用程序中以独立于平台的方式处理v8::internal::OS::DebugBreak
?
=== QJSEngine测试代码===
开发环境:Qt5和Windows SDK 7.1的QtCreator,在Windows XP SP3上
QJSEngineTest.pro:
TEMPLATE = app
QT -= gui
QT += core qml
CONFIG -= app_bundle
CONFIG += console
SOURCES += main.cpp
TARGET = QJSEngineTest
没有SEH的main.cpp(这会崩溃):
#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;
}
带有SEH的main.cpp(这不会崩溃,输出“致命异常”):
#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;
}
答案 0 :(得分:3)
我不相信有一种跨平台的方法来捕获V8致命错误,但即使有,或者如果有某种方法将它们捕获到你关心的所有平台上,我也不确定那是什么会买你的。
问题是V8使用global flag来记录是否发生了致命错误。一旦设置了该标志,V8将拒绝任何创建新JavaScript上下文的尝试,因此无论如何都没有意义继续。在捕获初始致命错误后尝试执行一些良性JavaScript代码。如果我是对的,你马上就会得到另一个致命的错误。
在我看来,正确的是Node和Qt将V8配置为不首先引发致命错误。既然V8支持隔离和内存约束,那么杀死致命错误的进程就不再合适了。不幸的是,看起来V8的错误处理代码还没有完全支持这些较新的功能,并且仍然假设内存不足的情况总是无法恢复。