Possible ExitEvent leak when BlockingCall() returns napi_closing
I found a possible native heap leak in the pty exit watcher when the thread-safe function is closing.
Files: src/unix/pty.cc, src/win/conpty.cc
Function: SetupExitCallback
Relevant Unix code:
auto callback = [](Napi::Env env, Napi::Function cb, ExitEvent *exit_event) {
cb.Call({Napi::Number::New(env, exit_event->exit_code),
Napi::Number::New(env, exit_event->signal_code)});
delete exit_event;
};
// ...
ExitEvent *exit_event = new ExitEvent;
// fill exit_event
auto status = tsfn.BlockingCall(exit_event, callback);
switch (status) {
case napi_closing:
break;
case napi_queue_full:
Napi::Error::Fatal("SetupExitCallback", "Queue was full");
case napi_ok:
if (tsfn.Release() != napi_ok) {
Napi::Error::Fatal("SetupExitCallback", "ThreadSafeFunction.Release() failed");
}
break;
}
The Windows implementation has the same ownership pattern.
The ExitEvent is deleted only by the JS-thread callback. If BlockingCall()
returns napi_closing, the item was not queued and that callback will not run.
The case napi_closing: branch then drops the only pointer to exit_event.
This is a small teardown-race leak: one ExitEvent per pty whose exit races
Node-API environment shutdown.
Suggested fix: delete exit_event in the napi_closing branch, where ownership
was not transferred to the callback queue.
Possible
ExitEventleak whenBlockingCall()returnsnapi_closingI found a possible native heap leak in the pty exit watcher when the thread-safe function is closing.
Files:
src/unix/pty.cc,src/win/conpty.ccFunction:
SetupExitCallbackRelevant Unix code:
The Windows implementation has the same ownership pattern.
The
ExitEventis deleted only by the JS-thread callback. IfBlockingCall()returns
napi_closing, the item was not queued and that callback will not run.The
case napi_closing:branch then drops the only pointer toexit_event.This is a small teardown-race leak: one
ExitEventper pty whose exit racesNode-API environment shutdown.
Suggested fix: delete
exit_eventin thenapi_closingbranch, where ownershipwas not transferred to the callback queue.