首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++插件中Node.js/Nan回调出现不频繁的段错误

C++插件中Node.js/Nan回调出现不频繁的段错误
EN

Stack Overflow用户
提问于 2017-04-05 06:54:17
回答 1查看 537关注 0票数 2

我正在使用Nan库做一个NodeJS插件,我遇到了一个问题,调用一个回调(在javascript端创建并传递给插件异步执行)将导致一个段错误-但大约每一万次左右才会运行一次。

每件事的操作都涉及到相当多的复杂性,但我希望有人能看到我遗漏的东西,或者能够弄清楚发生了什么。

C++回调函数是从javascript回调创建的,如下所示:

代码语言:javascript
复制
   auto nodeFunc = val.As<v8::Function>();
   auto nodeCb   = std::make_shared<Nan::Callback>(nodeFunc);

   auto callback = [nodeCb] (std::string err, std::string val) -> void {
        Nan::HandleScope     scope;
        v8::Local<v8::Value> argv[2];

       if (err.length() == 0) {
            auto isolate = v8::Isolate::GetCurrent();
            auto json    = v8::JSON::Parse(isolate, Nan::New(val).ToLocalChecked());
            auto object  = json.ToLocalChecked();
            argv[0] = Nan::Null();
            argv[1] = object;
        } else {
            argv[0] = Nan::Error(err.c_str());
            argv[1] = Nan::Null();
        }

        try {
            nodeCb->Call(2, argv);
        } catch (std::exception& ex) {
            std::cout << ex.what() << std::endl;
            Nan::ThrowReferenceError(ex.what());
        }
    };

在创建之后,它被传递到一个单独的线程,该线程最终使用uv_async_send()将回调发送到主libuv线程并执行它。这在大多数情况下都工作得很好,但在nodeCb->Call(2, argv)线路上很少会出现段错误。

如果任何人对这里发生的事情有任何见解,我将非常感谢。

另外,这里是来自gdb的调用堆栈,如果有任何帮助的话:

代码语言:javascript
复制
#0  0x00000000009870e0 in v8::Function::Call(v8::Local<v8::Value>, int, v8::Local<v8::Value>*) ()
#1  0x00000000010a562c in node::MakeCallback(node::Environment*, v8::Local<v8::Value>, v8::Local<v8::Function>, int, v8::Local<v8::Value>*) ()
#2  0x00000000010a5a98 in node::MakeCallback(v8::Isolate*, v8::Local<v8::Object>, v8::Local<v8::Function>, int, v8::Local<v8::Value>*) ()
#3  0x00007ffff47b4b30 in Nan::Callback::Call_ (this=0x20c3500, isolate=0x1ded750, target=..., argc=2,
    argv=0x7fffffffa430) at ../node_modules/nan/nan.h:1477
#4  0x00007ffff47b4a93 in Nan::Callback::Call (this=0x20c3500, argc=2, argv=0x7fffffffa430)
    at ../node_modules/nan/nan.h:1443
#5  0x00007ffff47b194b in detail::info::__lambda1::operator() (__closure=0x1e40710, err="",
    val="{\"index\":1,\"status\":1}") at ../node/utils.hpp:125
#6  0x00007ffff47b37f2 in std::_Function_handler<void(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >), detail::info::setElementValue(T&, v8::Local<v8::Value>, size_t) [with T = std::function<void(std::basic_string<char>, std::basic_string<char>)>; size_t = long unsigned int]::__lambda1>::_M_invoke(const std::_Any_data &, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >) (__functor=..., __args#0="", __args#1="")
    at /usr/include/c++/4.8.2/functional:2071
#7  0x00007ffff44cd339 in std::function<void (std::string, std::string)>::operator()(std::string, std::string) const (this=0x1e29c80, __args#0="", __args#1="")
    at /opt/rh/devtoolset-4/root/usr/include/c++/5.2.1/functional:2271
#8  0x00007ffff44e172c in std::_Bind<std::function<void (std::string, std::string)> (char const*, std::string)>::__call<void, , 0ul, 1ul>(std::tuple<>&&, std::_Index_tuple<0ul, 1ul>) (this=0x1e29c80,
    __args=<unknown type in /usr/local/lib/libSCPlay.so, CU 0x0, DIE 0x83e21>)
    at /opt/rh/devtoolset-4/root/usr/include/c++/5.2.1/functional:1074
#9  0x00007ffff44daec8 in std::_Bind<std::function<void (std::string, std::string)> (char const*, std::string)>::operator()<, void>() (this=0x1e29c80)
    at /opt/rh/devtoolset-4/root/usr/include/c++/5.2.1/functional:1133
#10 0x00007ffff44d3b58 in std::_Function_handler<void (), std::_Bind<std::function<void (std::string, std::string)> (char const*, std::string)> >::_M_invoke(std::_Any_data const&) (__functor=...)
    at /opt/rh/devtoolset-4/root/usr/include/c++/5.2.1/functional:1871
#11 0x00007ffff44fab0a in std::function<void ()>::operator()() const (this=0x7fffffffa650)
    at /opt/rh/devtoolset-4/root/usr/include/c++/5.2.1/functional:2271
#12 0x00007ffff44f890c in DeviceThread::asyncListener (handle=0x1efb9f0)
    at /home/scl37510/Projects/SCPlay2/lib/device_thread.cpp:124
#13 0x0000000001316b0b in uv__async_event (loop=0x1de7fe0 <default_loop_struct>, w=<optimized out>,
    nevents=<optimized out>) at ../deps/uv/src/unix/async.c:98
#14 0x0000000001316be3 in uv__async_io (loop=0x1de7fe0 <default_loop_struct>,
    w=0x1de81a8 <default_loop_struct+456>, events=<optimized out>) at ../deps/uv/src/unix/async.c:138
#15 0x00000000013271b0 in uv__io_poll (loop=loop@entry=0x1de7fe0 <default_loop_struct>, timeout=0)
    at ../deps/uv/src/unix/linux-core.c:380
#16 0x00000000013176c6 in uv_run (loop=0x1de7fe0 <default_loop_struct>, mode=UV_RUN_ONCE)
    at ../deps/uv/src/unix/core.c:354
#17 0x00000000010aabe0 in node::Start(int, char**) ()
#18 0x00007ffff6bf5b35 in __libc_start_main () from /lib64/libc.so.6
#19 0x00000000007b1f1d in _start ()

编辑:我已经创建了一个小得多的测试程序,看看我是否能找到错误的来源,我发现我可以通过将回调shared_ptr更改为常规指针,在nodeCb->Call(2,argv)行之后立即删除它来防止它。

这两者之间有没有语义上的差异会导致这种情况呢?

EN

回答 1

Stack Overflow用户

发布于 2017-08-07 23:40:04

使用shared_ptr包装回调是可疑的:

代码语言:javascript
复制
std::make_shared<Nan::Callback>(nodeFunc);

我不认为V8会喜欢这样处理引用。

Nan::Callback本身包含一个用来存储函数值的Persistent,因此您不必担心持久性。

在我写出这个答案之后,...I注意到了你的编辑。将shared_ptrV8内部句柄和引用混合使用具有潜在的危险。

如果您打算存储回调并立即将其删除,那么将代码重构为使用Nan::AsyncWorker可能会对您有所帮助。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43219049

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档