Possible crash: `Nan::ThrowError` called from `ClientWorker::Execute()`, which runs on the libuv threadpool
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 79/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- cpp, node.js
- Domain
- backend, embedded-iot
Research direction
Read src/linux/BTSerialPortBindingServer.cc and the ClientWorker declaration in src/BTSerialPortBindingServer.h; the issue identifies Execute() and the unsafe exception call. Check how NAN handles errors set from Execute(), then replace the call with SetErrorMessage() as shown. Confirm the error reaches the callback and the process survives without requiring Bluetooth hardware.
Written by the indexing model from the issue text.
Description
Nan::ThrowError called from ClientWorker::Execute(), which runs on the libuv threadpool
BTSerialPortBindingServer::ClientWorker is a Nan::AsyncWorker, so its
Execute() override runs on a libuv threadpool thread rather than the thread
that owns the V8 isolate. It raises a JavaScript exception from there:
// src/linux/BTSerialPortBindingServer.cc
void BTSerialPortBindingServer::ClientWorker::Execute(){
if(mBaton == nullptr){
return Nan::ThrowError("listen_baton_t is null!");
}
Nan::ThrowError reaches v8::Isolate::ThrowException, which may only be
called on the isolate's own thread. The declaration confirms the context:
// src/BTSerialPortBindingServer.h
class ClientWorker : public Nan::AsyncWorker {
void Execute() override;
void HandleOKCallback() override;
};
Reproduction
The behaviour does not depend on Bluetooth hardware; it follows from raising a
V8 exception inside Execute(). A minimal addon with the same shape:
class ThrowingWorker : public Nan::AsyncWorker {
public:
explicit ThrowingWorker(Nan::Callback *cb) : Nan::AsyncWorker(cb) {}
void Execute() override {
return Nan::ThrowError("raised from the worker thread");
}
void HandleOKCallback() override {
Nan::HandleScope scope;
v8::Local<v8::Value> argv[] = { Nan::Null() };
callback->Call(1, argv, async_resource);
}
};
const addon = require('./build/Release/poc.node');
process.on('uncaughtException', e => console.log('[uncaughtException]', e && e.message));
addon.run(() => console.log('[callback] ran'));
setTimeout(() => console.log('[alive] process survived'), 1000);
Node v22.17.1, macOS arm64, nan 2.x:
| worker body | exit code | output |
|---|---|---|
Nan::ThrowError(...) |
139 (SIGSEGV), 5/5 runs | none; the callback never runs |
SetErrorMessage(...) |
0, 3/3 runs | [callback] err = raised from the worker thread, [alive] process survived |
Suggested fix
NAN provides SetErrorMessage() for exactly this: record the message in
Execute() and let NAN deliver it on the loop thread through
HandleErrorCallback().
void BTSerialPortBindingServer::ClientWorker::Execute(){
if(mBaton == nullptr){
- return Nan::ThrowError("listen_baton_t is null!");
+ return SetErrorMessage("listen_baton_t is null!");
}
The existing HandleOKCallback() stays as it is; NAN calls
HandleErrorCallback() instead when an error message has been set, and the
default implementation passes the message to the stored callback as an Error.
- Dominant language
- C++
- Stars
- 205
- Forks
- 56
- PR merge metrics
- No merged PRs in 30d
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from lsongdev/node-bluetooth
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 45/100
lsongdev/node-bluetooth#61 ·
-
Difficulty 3/5 1-2 days Newbie friendliness 25/100
lsongdev/node-bluetooth#60 ·
-
Difficulty 4/5 3-5 days Newbie friendliness 30/100
lsongdev/node-bluetooth#57 · 1 comment · 2 reactions ·
-
Maintenance status?Open
Difficulty 1/5 Under an hour Newbie friendliness 10/100
lsongdev/node-bluetooth#55 · 8 comments ·
-
Battery status?Open
Difficulty 5/5 Over a week Newbie friendliness 20/100
lsongdev/node-bluetooth#54 · 1 comment ·
All issues in lsongdev/node-bluetooth
Similar issues
-
`IO.FS.realPath` reports every failure as `noFileOrDirectory` instead of classifying by `errno`Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
leanprover/lean4#15683 ·
Maintainers usually reply within 1 day
-
llvm.memcpy with destination align but no source align asserts "Missed Source alignment!"Possibly taken @pvelesko claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
KhronosGroup/SPIRV-LLVM-Translator#4093 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
Maintainers usually reply within 1 day
-
SIMQ silently truncates multi-query batch search to the first queryPossibly taken @LHT129 claimed this today. Openkind/bug module/index needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
antgroup/vsag#3080 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 Half a day Newbie friendliness 68/100
Maintainers usually reply within 1 day