You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 08:30:03