嵌入C++代码时NodeJS异常堆栈跟踪失效问题排查
问题:Node.js嵌入器API下未捕获异常丢失完整堆栈跟踪及异步钩子崩溃问题
1. 测试用JS代码
process.on('uncaughtException', (err, origin) => { fs.writeFileSync("error.txt", err.toString()); }) f = fs.createReadStream("blah"); f.on('data', (c) => { throw new Error("Test event error"); }); //OR setTimeout(function(){ throw new Error("Timeout error"); }, 2000)
2. Node命令行运行结果
使用node命令行运行上述代码时,error.txt中包含完整的异常堆栈跟踪:
at Timeout._onTimeout (init.js:93:11) at listOnTimeout (node:internal/timers:573:17) at process.processTimers (node:internal/timers:514:7) { [stack]: 'Error: Timeout error\n' + ' at Timeout._onTimeout (init.js:93:11)\n' + ' at listOnTimeout (node:internal/timers:573:17)\n' + ' at process.processTimers (node:internal/timers:514:7)', [message]: 'Timeout error'
3. C++嵌入器API运行的异常表现
通过Node.js嵌入器API在C++中运行相同代码时,出现以下问题:
- 普通回调抛出异常时,仅能获取错误消息,无完整堆栈跟踪:
[Error: Error thrown from setTimeout] { [stack]: 'Error: Error thrown from setTimeout', [message]: 'Error thrown from setTimeout' }
- 将回调改为
async时,仅能显示部分堆栈(如init.js:93),嵌套setTimeout场景仍无完整堆栈 - 从
setImmediate回调抛出异常时,出现async hook stack has become corrupted崩溃,需将setImmediate替换为setTimeout(cb,0)才能正常运行
4. C++初始化代码示例
int ret = uv_loop_init(&loop); if(ret != 0){ throw LException("Failed to initialize loop: " + LString(uv_err_name(ret))); } v8::Isolate* isolate = node::NewIsolate(allocator, loop, platform) isolate->SetAbortOnUncaughtExceptionCallback([](v8::Isolate*) -> bool{ return false; //UNCAUGHT EXCEPTION IS CAPTURED IN JS CODE (This function gets never executed, because nodeJS registers it's own callback) }); isolate->SetPromiseRejectCallback([](v8::PromiseRejectMessage message) -> void{ //PROMISE REJECTION STACK TRACE WORKS FINE ... ... ... }); v8::Isolate::Scope isolate_scope(isolate); //Stack allocated, use every time, when an interaction with isolate is needed in local scope // Set up a new v8::Context. (used ONLY for initialization) isolate->SetCaptureStackTraceForUncaughtExceptions(true, 30); v8::HandleScope handle_scope(isolate); v8::Local<v8::Context> context = node::NewContext(isolate, templ); if (context.IsEmpty()) { fprintf(stderr, "%s: Failed to initialize V8 Context\n", args[0].c_str()); return 1; } // The v8::Context needs to be entered when node::CreateEnvironment() and // node::LoadEnvironment() are being called. v8::Context::Scope context_scope(context); std::vector<std::string> errors; this->isolate_data = node::CreateIsolateData(isolate, this->getLoop(), platform, this->getDefaultIsolate()->getAllocator().get()); this->env = node::CreateEnvironment(isolate_data, context, args, exec_args); ... ... v8::MaybeLocal<v8::Value> loadenv_ret = node::LoadEnvironment(env, [&](const node::StartExecutionCallbackInfo& info) -> v8::MaybeLocal<v8::Value>{ this->intern_require = v8::Global<v8::Function>(isolate, info.native_require); this->process.Reset(isolate, info.process_object); v8::Local<v8::Object> octx = context->Global(); octx->Set(context, v8::String::NewFromUtf8Literal(isolate, "process"), info.process_object); v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, "process.on('uncaughtException', function(err){ __lt_reportUncaughtError(err); return false; }); // process.on('unhandledRejection', function(err, prom){ process.exit(255); __lt_reportUncaughtError(err) })").ToLocalChecked(); v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked(); script->Run(context); return v8::Number::New(isolate, 0.0d); }); if(loadenv_ret.IsEmpty()){ // There has been a JS exception. throw LException("node::LoadEnvironment returned empty result"L, "NodeInstance::init()"L); } ... ... v8::Isolate::Scope iscope(isolate->get()); v8::HandleScope hscope(isolate->get()); v8::Context::Scope cscope(lcontext); uint32_t sl = scripts.size(); for(uint32_t i = 0; i < sl; i++){ v8::Local<v8::Script> lscript = v8::Local<v8::Script>::New(isolate->get(), scripts[i]); v8::Local<v8::Context> scriptctx = v8::Local<v8::Context>::New(isolate->get(), contexts[i]); v8::Local<v8::Object> glb = scriptctx->Global(); lscript->Run(lcontext); }
排查请求
已提交Bug,但希望确认是否是初始化过程中遗漏了某些配置、Scope或Context错误导致上述问题,是否存在此类常见错误,恳请协助排查。
内容的提问来源于stack exchange,提问作者ddd ddd111111
相关产品推荐
相关产品推荐

