-
Notifications
You must be signed in to change notification settings - Fork 29.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
napi_threadsafe_function is very hard to use safely #55706
Labels
node-api
Issues and PRs related to the Node-API.
Comments
Is that something you would be able to submit a PR for ? |
Sure, I can give it a go |
mika-fischer
added a commit
to mika-fischer/node
that referenced
this issue
Nov 16, 2024
Other threads can still hold a valid handle to the tsfn after finalization if finalization was triggered by - release with napi_tsfn_abort, or - environment shutdown Handle this by: - protecting finalization itself with the mutex - if necessary, delay deletion after finalization to when thread_count drops to 0 Fixes: nodejs#55706
mika-fischer
added a commit
to mika-fischer/node
that referenced
this issue
Nov 16, 2024
Other threads can still hold a valid handle to the tsfn after finalization if finalization was triggered by - release with napi_tsfn_abort, or - environment shutdown Handle this by: - protecting finalization itself with the mutex - if necessary, delay deletion after finalization to when thread_count drops to 0 - releasing all resources as soon as possible before deletion Fixes: nodejs#55706
This fixes the test here https://github.com/mika-fischer/node-bug-napi-tsfn I'll try to integrate the test into node next week, don't have any more free time this weekend. |
@mika-fischer thanks. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Version
v22.10.0
Platform
Subsystem
node-api
What steps will reproduce the bug?
The handle obtained with
napi_create_threadsafe_function
is supposed to be usable by arbitrary threads.In particular, the following operations should be safe to call from arbitrary threads (until that thread calls
napi_release_threadsafe_function
or receivesnapi_closing
fromnapi_call_threadsafe_function
):napi_get_threadsafe_function_context
,napi_call_threadsafe_function
,napi_acquire_threadsafe_function
, andnapi_release_threadsafe_function
.However, this is currently not the case.
In particular, in the face of Node.js environment shutdown there are data races and use-after-frees that occur when threads call any of these functions during or after the cleanup that happens when the Node.js environment shuts down.
There are two main issues I already found:
napi_call_threadsafe_function
concurrently, this leads to a data race on the queue internals hereSee https://github.com/mika-fischer/node-bug-napi-tsfn for a detailed reproduction of the issue on Linux using valgrind
While working around this is technically possible (see src/run/fixed.hpp) it involves attaching a finalizer in order to track the finalization state in an external flag, whose lifetime must be managed via a shared_ptr or similar and all access to the TSFN must be protected by another mutex (or read-write-lock). This makes the whole thing very unergonomic to use and I'm pretty sure nobody will jump through these hoops.
It should also be relatively easy to fix and not break API or ABI
How often does it reproduce? Is there a required condition?
Always
What is the expected behavior? Why is that the expected behavior?
napi_release_threadsafe_function
ornapi_call_threadsafe_function
decreases the thread_count to zero.napi_get_threadsafe_function_context
should return the stored context pointer as usualnapi_call_threadsafe_function
should returnnapi_closing
, decrease the thread_count and if it falls to zero delete the TSFNnapi_acquire_threadsafe_function
should returnnapi_closing
napi_release_threadsafe_function
should returnnapi_ok
, decrease the thread_count and if it falls to zero delete the TSFNWhat do you see instead?
data races & use-after-frees leading to crashes
Additional information
No response
The text was updated successfully, but these errors were encountered: