fix(napi): drop buffer inner data only when Reference count is 0

This commit is contained in:
LongYinan 2022-07-07 00:01:09 +08:00
parent 661b418eb6
commit bffc49f11a
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
2 changed files with 18 additions and 8 deletions

View file

@ -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<Arc<()>>,
inner: &'static mut [u8],
capacity: usize,
pub(crate) data_reference: Option<Arc<()>>,
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,
)
}

View file

@ -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,
));
}
}
}
}