chore(napi): show tips if create different buffers with same data

This commit is contained in:
LongYinan 2022-04-11 14:31:09 +08:00
parent 1d1c1706d5
commit c605911cdf
2 changed files with 26 additions and 0 deletions

View file

@ -1,10 +1,19 @@
#[cfg(debug_assertions)]
use std::collections::HashSet;
use std::mem; use std::mem;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::ptr; use std::ptr;
use std::slice; use std::slice;
#[cfg(debug_assertions)]
use std::sync::Mutex;
use crate::{bindgen_prelude::*, check_status, sys, Result, ValueType}; use crate::{bindgen_prelude::*, check_status, sys, Result, ValueType};
#[cfg(debug_assertions)]
thread_local! {
pub (crate) static BUFFER_DATA: Mutex<HashSet<*mut u8>> = Default::default();
}
/// Zero copy u8 vector shared between rust and napi. /// Zero copy u8 vector shared between rust and napi.
/// Auto reference the raw JavaScript value, and release it when dropped. /// Auto reference the raw JavaScript value, and release it when dropped.
/// So it is safe to use it in `async fn`, the `&[u8]` under the hood will not be dropped until the `drop` called. /// So it is safe to use it in `async fn`, the `&[u8]` under the hood will not be dropped until the `drop` called.
@ -53,6 +62,16 @@ impl Buffer {
impl From<Vec<u8>> for Buffer { impl From<Vec<u8>> for Buffer {
fn from(mut data: Vec<u8>) -> Self { fn from(mut data: Vec<u8>) -> Self {
let inner_ptr = data.as_mut_ptr(); let inner_ptr = data.as_mut_ptr();
#[cfg(debug_assertions)]
{
let is_existed = BUFFER_DATA.with(|buffer_data| {
let buffer = buffer_data.lock().expect("Unlock buffer data failed");
buffer.contains(&inner_ptr)
});
if is_existed {
panic!("Share the same data between different buffers is not allowed, see: https://github.com/nodejs/node/issues/32463#issuecomment-631974747");
}
}
let len = data.len(); let len = data.len();
let capacity = data.capacity(); let capacity = data.capacity();
mem::forget(data); mem::forget(data);

View file

@ -52,6 +52,13 @@ pub unsafe extern "C" fn drop_buffer(
finalize_hint: *mut c_void, finalize_hint: *mut c_void,
) { ) {
let length_ptr = finalize_hint as *mut (usize, usize); let length_ptr = finalize_hint as *mut (usize, usize);
#[cfg(debug_assertions)]
{
js_values::BUFFER_DATA.with(|buffer_data| {
let mut buffer = buffer_data.lock().expect("Unlock Buffer data failed");
buffer.remove(&(finalize_data as *mut u8));
});
}
unsafe { unsafe {
let (length, cap) = *Box::from_raw(length_ptr); let (length, cap) = *Box::from_raw(length_ptr);
mem::drop(Vec::from_raw_parts(finalize_data as *mut u8, length, cap)); mem::drop(Vec::from_raw_parts(finalize_data as *mut u8, length, cap));