diff --git a/crates/napi/src/bindgen_runtime/js_values/buffer.rs b/crates/napi/src/bindgen_runtime/js_values/buffer.rs index d72e6d07..c5879510 100644 --- a/crates/napi/src/bindgen_runtime/js_values/buffer.rs +++ b/crates/napi/src/bindgen_runtime/js_values/buffer.rs @@ -1,5 +1,6 @@ #[cfg(debug_assertions)] use std::collections::HashSet; +use std::ffi::c_void; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr; @@ -20,9 +21,9 @@ thread_local! { /// So it is safe to use it in `async fn`, the `&[u8]` under the hood will not be dropped until the `drop` called. /// Clone will create a new `Reference` to the same underlying `JavaScript Buffer`. pub struct Buffer { - data_reference: Option>, - inner: &'static mut [u8], - capacity: usize, + pub(crate) data_reference: Option>, + pub(crate) inner: &'static mut [u8], + pub(crate) capacity: usize, raw: Option<(sys::napi_ref, sys::napi_env)>, } @@ -181,13 +182,14 @@ impl ToNapiValue for Buffer { // the same data pointer if it's 0x0. unsafe { sys::napi_create_buffer(env, len, ptr::null_mut(), &mut ret) } } else { + let val_ptr = val.inner.as_mut_ptr(); unsafe { sys::napi_create_external_buffer( env, len, - val.inner.as_mut_ptr() as *mut _, + val_ptr as *mut c_void, Some(drop_buffer), - Box::into_raw(Box::new((len, val.capacity))) as *mut _, + Box::into_raw(Box::new(val)) as *mut c_void, &mut ret, ) } diff --git a/crates/napi/src/bindgen_runtime/mod.rs b/crates/napi/src/bindgen_runtime/mod.rs index f013365f..7b418472 100644 --- a/crates/napi/src/bindgen_runtime/mod.rs +++ b/crates/napi/src/bindgen_runtime/mod.rs @@ -1,6 +1,7 @@ use std::ffi::c_void; use std::mem; use std::rc::Rc; +use std::sync::Arc; pub use callback_info::*; pub use ctor::ctor; @@ -66,7 +67,6 @@ pub unsafe extern "C" fn drop_buffer( finalize_data: *mut c_void, finalize_hint: *mut c_void, ) { - let length_ptr = finalize_hint as *mut (usize, usize); #[cfg(debug_assertions)] { js_values::BUFFER_DATA.with(|buffer_data| { @@ -75,7 +75,15 @@ pub unsafe extern "C" fn drop_buffer( }); } unsafe { - let (length, cap) = *Box::from_raw(length_ptr); - mem::drop(Vec::from_raw_parts(finalize_data as *mut u8, length, cap)); + let buf = Box::from_raw(finalize_hint as *mut Buffer); + if let Some(data_reference) = buf.data_reference.as_ref() { + if Arc::strong_count(data_reference) == 0 { + mem::drop(Vec::from_raw_parts( + finalize_data as *mut u8, + buf.inner.len(), + buf.capacity, + )); + } + } } }