Skip to content
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

ThreadSafeFunction memory violation in ThreadSafeFinalize #632

Closed
averrez opened this issue Dec 14, 2019 · 1 comment
Closed

ThreadSafeFunction memory violation in ThreadSafeFinalize #632

averrez opened this issue Dec 14, 2019 · 1 comment

Comments

@averrez
Copy link

averrez commented Dec 14, 2019

Hi everyone,

I've been experiencing random rare crashes in both Mac and Windows when Napi::ThreadSafeFunction is deallocated. My investigation brought me to the New function:

template <typename ResourceString, typename ContextType,
          typename Finalizer, typename FinalizerDataType>
inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
                                                  const Function& callback,
                                                  const Object& resource,
                                                  ResourceString resourceName,
                                                  size_t maxQueueSize,
                                                  size_t initialThreadCount,
                                                  ContextType* context,
                                                  Finalizer finalizeCallback,
                                                  FinalizerDataType* data,
                                                  napi_finalize wrapper) {
  static_assert(details::can_make_string<ResourceString>::value
      || std::is_convertible<ResourceString, napi_value>::value,
      "Resource name should be convertible to the string type");

  ThreadSafeFunction tsfn; // <---- Stack allocated.
  auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
      FinalizerDataType>({ data, finalizeCallback, &tsfn._tsfn }); // <---- Pointer to ivar stored
  napi_status status = napi_create_threadsafe_function(env, callback, resource,
      Value::From(env, resourceName), maxQueueSize, initialThreadCount,
      finalizeData, wrapper, context, CallJS, &tsfn._tsfn);
  if (status != napi_ok) {
    delete finalizeData;
    NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunction());
  }

  return tsfn;
}

I believe that the issue is that ThreadSafeFunction tsfn; is stack-allocated and a pointer to its ivar is stored in the ThreadSafeFinalize: { data, finalizeCallback, &tsfn._tsfn }

When function is being destroyed, the finalizer is called with this code in it:

if (finalizeData->tsfn) {
      *finalizeData->tsfn = nullptr;
}

If I understand correctly, it writes nullptr to the captured pointer, which is long gone by now.
Also, there are no other references in the code to that member. It feels like it's not used anywhere, and storing and nullifying it is redundant?

I also tested it with Xcode memory sanitizer and it confirmed that stack memory is being corrupted from ThreadSafeFinalize.

Thank you.

@KevinEady
Copy link
Contributor

Hi @averrez ,

Thanks for spotting this. Yes, I think this is a leftover of the original implementation of holding the napi_threadsafe_function inside a std::unique_ptr and should have been removed in #546 but was overlooked. I will take this issue and fix with an incoming PR.

KevinEady added a commit to KevinEady/node-addon-api that referenced this issue Dec 16, 2019
Removes leftover cleanup in finalizer that was part of the original TSFN
implementation.

Fixes: nodejs#632
kevindavies8 added a commit to kevindavies8/node-addon-api-Develop that referenced this issue Aug 24, 2022
Removes leftover cleanup in finalizer that was part of the original TSFN
implementation.

Fixes: nodejs/node-addon-api#632
PR-URL: nodejs/node-addon-api#636
Reviewed-By: Gabriel Schulhof <[email protected]>
Marlyfleitas added a commit to Marlyfleitas/node-api-addon-Development that referenced this issue Aug 26, 2022
Removes leftover cleanup in finalizer that was part of the original TSFN
implementation.

Fixes: nodejs/node-addon-api#632
PR-URL: nodejs/node-addon-api#636
Reviewed-By: Gabriel Schulhof <[email protected]>
wroy7860 added a commit to wroy7860/addon-api-benchmark-node that referenced this issue Sep 19, 2022
Removes leftover cleanup in finalizer that was part of the original TSFN
implementation.

Fixes: nodejs/node-addon-api#632
PR-URL: nodejs/node-addon-api#636
Reviewed-By: Gabriel Schulhof <[email protected]>
johnfrench3 pushed a commit to johnfrench3/node-addon-api-git that referenced this issue Aug 11, 2023
Removes leftover cleanup in finalizer that was part of the original TSFN
implementation.

Fixes: nodejs/node-addon-api#632
PR-URL: nodejs/node-addon-api#636
Reviewed-By: Gabriel Schulhof <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants