Possible Nan::Callback leak in read() on a closed connection
I found a possible native heap leak in BTSerialPortBinding::Read. On the
closed-connection branch it allocates a Nan::Callback, calls it synchronously, and
never deletes it. The same code is present on both the Linux and Windows bindings.
Files: src/linux/BTSerialPortBinding.cc, src/windows/BTSerialPortBinding.cc
Function: BTSerialPortBinding::Read
// callback with an error if the connection has been closed.
if (rfcomm->s == 0) {
Local<Value> argv[2];
argv[0] = Nan::Error("The connection has been closed");
argv[1] = Nan::Undefined();
Nan::AsyncResource resource("bluetooth-serial-port:Read");
Nan::Callback *nc = new Nan::Callback(cb);
nc->Call(2, argv, &resource); // nc is used but never deleted
} else {
read_baton_t *baton = new read_baton_t();
baton->rfcomm = rfcomm;
baton->cb = new Nan::Callback(cb);
baton->request.data = baton;
baton->rfcomm->Ref();
uv_queue_work(uv_default_loop(), &baton->request, EIO_Read, (uv_after_work_cb)EIO_AfterRead);
}
On the rfcomm->s == 0 branch, nc is a raw heap Nan::Callback (which holds a
v8::Persistent to the JS function). It is invoked synchronously but never deleted,
and unlike the else branch it is never handed to a worker that would free it. Each
read() on an already-closed connection leaks one Nan::Callback plus its retained
function reference — a common pattern is a read loop that keeps calling read() after
the peer disconnects, leaking once per call.
The project already knows the correct shape: the server variant handles the same
closed-connection branch with an owning smart pointer
(src/linux/BTSerialPortBindingServer.cc: std::unique_ptr<Nan::Callback> nc(new Nan::Callback(cb));).
Suggested fix: give nc the same ownership, e.g. std::unique_ptr<Nan::Callback> nc(new Nan::Callback(cb)); nc->Call(2, argv, &resource);, or delete nc; after the call.
Possible
Nan::Callbackleak inread()on a closed connectionI found a possible native heap leak in
BTSerialPortBinding::Read. On theclosed-connection branch it allocates a
Nan::Callback, calls it synchronously, andnever deletes it. The same code is present on both the Linux and Windows bindings.
Files:
src/linux/BTSerialPortBinding.cc,src/windows/BTSerialPortBinding.ccFunction:
BTSerialPortBinding::ReadOn the
rfcomm->s == 0branch,ncis a raw heapNan::Callback(which holds av8::Persistentto the JS function). It is invoked synchronously but neverdeleted,and unlike the
elsebranch it is never handed to a worker that would free it. Eachread()on an already-closed connection leaks oneNan::Callbackplus its retainedfunction reference — a common pattern is a read loop that keeps calling
read()afterthe peer disconnects, leaking once per call.
The project already knows the correct shape: the server variant handles the same
closed-connection branch with an owning smart pointer
(
src/linux/BTSerialPortBindingServer.cc:std::unique_ptr<Nan::Callback> nc(new Nan::Callback(cb));).Suggested fix: give
ncthe same ownership, e.g.std::unique_ptr<Nan::Callback> nc(new Nan::Callback(cb)); nc->Call(2, argv, &resource);, ordelete nc;after the call.