fix(napi): should also delete the reference while dropping the Buffer

This commit is contained in:
LongYinan 2022-10-02 09:38:11 +08:00
parent 4279291f4b
commit 47de6301ee
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
6 changed files with 53 additions and 36 deletions

View file

@ -67,6 +67,11 @@ macro_rules! impl_typed_array {
crate::check_status_or_throw!( crate::check_status_or_throw!(
env, env,
unsafe { sys::napi_reference_unref(env, ref_, &mut 0) }, unsafe { sys::napi_reference_unref(env, ref_, &mut 0) },
"Failed to unref Buffer reference in drop"
);
crate::check_status_or_throw!(
env,
unsafe { sys::napi_delete_reference(env, ref_) },
"Failed to delete Buffer reference in drop" "Failed to delete Buffer reference in drop"
); );
return; return;

View file

@ -25,23 +25,27 @@ pub struct Buffer {
pub(crate) len: usize, pub(crate) len: usize,
pub(crate) capacity: usize, pub(crate) capacity: usize,
raw: Option<(sys::napi_ref, sys::napi_env)>, raw: Option<(sys::napi_ref, sys::napi_env)>,
// use it as ref count pub(crate) ref_count: Arc<()>,
pub(crate) drop_in_vm: Arc<()>,
} }
impl Drop for Buffer { impl Drop for Buffer {
fn drop(&mut self) { fn drop(&mut self) {
if let Some((ref_, env)) = self.raw { if Arc::strong_count(&self.ref_count) == 1 {
check_status_or_throw!( if let Some((ref_, env)) = self.raw {
env, let mut ref_count = 0;
unsafe { sys::napi_reference_unref(env, ref_, &mut 0) }, check_status_or_throw!(
"Failed to unref Buffer reference in drop" env,
); unsafe { sys::napi_reference_unref(env, ref_, &mut ref_count) },
return; "Failed to unref Buffer reference in drop"
} );
check_status_or_throw!(
if Arc::strong_count(&self.drop_in_vm) == 1 { env,
unsafe { Vec::from_raw_parts(self.inner.as_ptr(), self.len, self.capacity) }; unsafe { sys::napi_delete_reference(env, ref_) },
"Failed to delete Buffer reference in drop"
);
} else {
unsafe { Vec::from_raw_parts(self.inner.as_ptr(), self.len, self.capacity) };
}
} }
} }
} }
@ -50,24 +54,15 @@ impl Drop for Buffer {
// without synchronization. Also see the docs for the `AsMut` impl. // without synchronization. Also see the docs for the `AsMut` impl.
unsafe impl Send for Buffer {} unsafe impl Send for Buffer {}
impl Buffer { impl Clone for Buffer {
pub fn clone(&mut self, env: &Env) -> Result<Self> { fn clone(&self) -> Self {
let raw = if let Some((ref_, _)) = self.raw { Self {
check_status!(
unsafe { sys::napi_reference_ref(env.0, ref_, &mut 0) },
"Failed to ref Buffer reference in Buffer::clone"
)?;
Some((ref_, env.0))
} else {
None
};
Ok(Self {
inner: self.inner, inner: self.inner,
len: self.len, len: self.len,
capacity: self.capacity, capacity: self.capacity,
raw, raw: self.raw,
drop_in_vm: self.drop_in_vm.clone(), ref_count: self.ref_count.clone(),
}) }
} }
} }
@ -95,7 +90,7 @@ impl From<Vec<u8>> for Buffer {
len, len,
capacity, capacity,
raw: None, raw: None,
drop_in_vm: Arc::new(()), ref_count: Arc::new(()),
} }
} }
} }
@ -184,7 +179,7 @@ impl FromNapiValue for Buffer {
len, len,
capacity: len, capacity: len,
raw: Some((ref_, env)), raw: Some((ref_, env)),
drop_in_vm: Arc::new(()), ref_count: Arc::new(()),
}) })
} }
} }
@ -227,9 +222,16 @@ impl ToNapiValue for Buffer {
} }
} }
impl ToNapiValue for &Buffer {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
let buf = val.clone();
unsafe { ToNapiValue::to_napi_value(env, buf) }
}
}
impl ToNapiValue for &mut Buffer { impl ToNapiValue for &mut Buffer {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
let buf = val.clone(&Env::from(env))?; let buf = val.clone();
unsafe { ToNapiValue::to_napi_value(env, buf) } unsafe { ToNapiValue::to_napi_value(env, buf) }
} }
} }

View file

@ -73,7 +73,7 @@ pub unsafe extern "C" fn raw_finalize_unchecked<T: ObjectFinalize>(
#[doc(hidden)] #[doc(hidden)]
pub unsafe extern "C" fn drop_buffer( pub unsafe extern "C" fn drop_buffer(
_env: sys::napi_env, _env: sys::napi_env,
finalize_data: *mut c_void, #[allow(unused)] finalize_data: *mut c_void,
finalize_hint: *mut c_void, finalize_hint: *mut c_void,
) { ) {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]

View file

@ -68,8 +68,6 @@ impl Task for AsyncBuffer {
} }
#[napi] #[napi]
fn async_reduce_buffer(mut buf: Buffer, env: Env) -> Result<AsyncTask<AsyncBuffer>> { fn async_reduce_buffer(buf: Buffer) -> Result<AsyncTask<AsyncBuffer>> {
Ok(AsyncTask::new(AsyncBuffer { Ok(AsyncTask::new(AsyncBuffer { buf: buf.clone() }))
buf: buf.clone(&env)?,
}))
} }

View file

@ -18,6 +18,8 @@ while (true) {
api.arrayBufferConvert( api.arrayBufferConvert(
Uint8Array.from(Array.from({ length: 1024 * 10240 }).fill(1)), Uint8Array.from(Array.from({ length: 1024 * 10240 }).fill(1)),
) )
api.bufferPassThrough(Buffer.from('hello world'.repeat(1024 * 1024)))
api.arrayBufferPassThrough(Uint8Array.from('hello world'.repeat(1024 * 1024)))
if (i % 10 === 0) { if (i % 10 === 0) {
await setTimeout(100) await setTimeout(100)
displayMemoryUsageFromNode(initialMemoryUsage) displayMemoryUsageFromNode(initialMemoryUsage)

View file

@ -161,3 +161,13 @@ pub fn array_buffer_convert(array_buffer: Uint8Array) -> Uint8Array {
pub fn array_buffer_len() -> u32 { pub fn array_buffer_len() -> u32 {
Uint8Array::new(vec![1; 1024 * 10240]).len() as u32 Uint8Array::new(vec![1; 1024 * 10240]).len() as u32
} }
#[napi]
pub fn buffer_pass_through(buffer: Buffer) -> Buffer {
buffer
}
#[napi]
pub fn array_buffer_pass_through(array_buffer: Uint8Array) -> Uint8Array {
array_buffer
}