From 99e17c7294fe9b8fca2043c8f0fa5f0b4ba6340f Mon Sep 17 00:00:00 2001 From: messense Date: Sat, 20 Aug 2022 22:40:26 +0800 Subject: [PATCH] fix(napi): segfault when `ThreadsafeFunction`'s callback closure captures data (#1281) --- crates/napi/src/threadsafe_function.rs | 8 ++++---- examples/napi/__test__/typegen.spec.ts.md | 1 + examples/napi/__test__/typegen.spec.ts.snap | Bin 3566 -> 3583 bytes examples/napi/__test__/values.spec.ts | 10 ++++++++++ examples/napi/index.d.ts | 1 + examples/napi/src/threadsafe_function.rs | 17 ++++++++++++++++- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/crates/napi/src/threadsafe_function.rs b/crates/napi/src/threadsafe_function.rs index 8ce36e20..4912d6e6 100644 --- a/crates/napi/src/threadsafe_function.rs +++ b/crates/napi/src/threadsafe_function.rs @@ -214,9 +214,9 @@ impl ThreadsafeFunction { async_resource_name, max_queue_size, initial_thread_count, - ptr, - Some(thread_finalize_cb::), aborted_ptr as *mut c_void, + Some(thread_finalize_cb::), + ptr, Some(call_js_cb::), &mut raw_tsfn, ) @@ -355,8 +355,8 @@ unsafe extern "C" fn thread_finalize_cb( R: 'static + Send + FnMut(ThreadSafeCallContext) -> Result>, { // cleanup - drop(unsafe { Box::::from_raw(finalize_data.cast()) }); - let aborted = unsafe { Arc::>::from_raw(finalize_hint.cast()) }; + drop(unsafe { Box::::from_raw(finalize_hint.cast()) }); + let aborted = unsafe { Arc::>::from_raw(finalize_data.cast()) }; let mut is_aborted = aborted.lock().unwrap(); *is_aborted = true; } diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index a05091fd..bcf1735e 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -193,6 +193,7 @@ Generated by [AVA](https://avajs.dev). export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void␊ export function threadsafeFunctionFatalMode(cb: (...args: any[]) => any): void␊ export function threadsafeFunctionFatalModeError(cb: (...args: any[]) => any): void␊ + export function threadsafeFunctionClosureCapture(func: (...args: any[]) => any): void␊ export function useTokioWithoutAsync(): void␊ export function getBuffer(): Buffer␊ export function appendBuffer(buf: Buffer): Buffer␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index 69867ce3d6c6ff36fa1635edbfc40b60620c4856..6091812b16d5a18d472aa412528843047abafbf3 100644 GIT binary patch literal 3583 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 F002??;#>d# literal 3566 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 diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index 39fcd131..bf351b0b 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -50,6 +50,7 @@ import { bigintGetU64AsString, callThreadsafeFunction, threadsafeFunctionThrowError, + threadsafeFunctionClosureCapture, asyncPlus100, getGlobal, getUndefined, @@ -691,6 +692,15 @@ Napi4Test('throw error from thread safe function', async (t) => { t.is(err!.message, 'ThrowFromNative') }) +Napi4Test('thread safe function closure capture data', (t) => { + return new Promise((resolve) => { + threadsafeFunctionClosureCapture(() => { + resolve() + t.pass() + }) + }) +}) + Napi4Test('resolve value from thread safe function fatal mode', async (t) => { const tsfnFatalMode = new Promise((resolve) => { threadsafeFunctionFatalMode(resolve) diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 30690e82..e7c74e2b 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -183,6 +183,7 @@ export function callThreadsafeFunction(callback: (...args: any[]) => any): void export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void export function threadsafeFunctionFatalMode(cb: (...args: any[]) => any): void export function threadsafeFunctionFatalModeError(cb: (...args: any[]) => any): void +export function threadsafeFunctionClosureCapture(func: (...args: any[]) => any): void export function useTokioWithoutAsync(): void export function getBuffer(): Buffer export function appendBuffer(buf: Buffer): Buffer diff --git a/examples/napi/src/threadsafe_function.rs b/examples/napi/src/threadsafe_function.rs index f0cc24c3..089fa858 100644 --- a/examples/napi/src/threadsafe_function.rs +++ b/examples/napi/src/threadsafe_function.rs @@ -3,7 +3,7 @@ use std::thread; use napi::{ bindgen_prelude::*, threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode}, - JsBoolean, + JsBoolean, JsString, }; #[napi] @@ -61,3 +61,18 @@ pub fn threadsafe_function_fatal_mode_error(cb: JsFunction) -> Result<()> { }); Ok(()) } + +#[napi] +fn threadsafe_function_closure_capture(func: JsFunction) -> napi::Result<()> { + let str = "test"; + let tsfn: ThreadsafeFunction<()> = func + .create_threadsafe_function(0, move |_| { + println!("{}", str); // str is NULL at this point + Ok(Vec::::new()) + }) + .unwrap(); + + tsfn.call(Ok(()), ThreadsafeFunctionCallMode::NonBlocking); + + Ok(()) +}