From c6768569eee23a9bd5785904d48f4af852ad5d92 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Wed, 10 Feb 2021 11:27:43 -0800 Subject: [PATCH] Fix as_slice and as_mut_slice for empty Buffers and ArrayBuffers These buffers may have NULL as their address, which slice::from_raw_parts does not allow. --- src/types/binary.rs | 20 ++++++++++----- test/dynamic/lib/objects.js | 36 +++++++++++++++++++++++++++ test/dynamic/native/src/js/objects.rs | 24 ++++++++++++++++++ test/dynamic/native/src/lib.rs | 4 +++ test/napi/src/js/objects.rs | 24 ++++++++++++++++++ test/napi/src/lib.rs | 4 +++ 6 files changed, 106 insertions(+), 6 deletions(-) diff --git a/src/types/binary.rs b/src/types/binary.rs index e4d3cd74b..2845c406e 100644 --- a/src/types/binary.rs +++ b/src/types/binary.rs @@ -138,9 +138,13 @@ impl<'a> BinaryData<'a> { /// # } /// ``` pub fn as_slice(self) -> &'a [T] { - let base = unsafe { mem::transmute(self.base) }; - let len = self.size / mem::size_of::(); - unsafe { slice::from_raw_parts(base, len) } + if self.size == 0 { + &[] + } else { + let base = unsafe { mem::transmute(self.base) }; + let len = self.size / mem::size_of::(); + unsafe { slice::from_raw_parts(base, len) } + } } /// Produces a mutable slice as a view into the contents of this buffer. @@ -160,9 +164,13 @@ impl<'a> BinaryData<'a> { /// # } /// ``` pub fn as_mut_slice(self) -> &'a mut [T] { - let base = unsafe { mem::transmute(self.base) }; - let len = self.size / mem::size_of::(); - unsafe { slice::from_raw_parts_mut(base, len) } + if self.size == 0 { + &mut [] + } else { + let base = unsafe { mem::transmute(self.base) }; + let len = self.size / mem::size_of::(); + unsafe { slice::from_raw_parts_mut(base, len) } + } } /// Produces the length of the buffer, in bytes. diff --git a/test/dynamic/lib/objects.js b/test/dynamic/lib/objects.js index 83eda0f51..5fa3e3fbd 100644 --- a/test/dynamic/lib/objects.js +++ b/test/dynamic/lib/objects.js @@ -57,6 +57,14 @@ describe('JsObject', function() { assert.equal(addon.read_array_buffer_with_borrow(b, 3), 89898989); }); + it('correctly reads an empty ArrayBuffer using the borrow API', function() { + let nonempty = Uint8Array.from([1, 2, 3]); + assert.equal(addon.sum_array_buffer_with_borrow(nonempty.buffer), 6); + + let empty = Uint8Array.from([]); + assert.equal(addon.sum_array_buffer_with_borrow(empty.buffer), 0); + }); + it('correctly writes to an ArrayBuffer using the lock API', function() { var b = new ArrayBuffer(16); addon.write_array_buffer_with_lock(b, 0, 999); @@ -81,6 +89,16 @@ describe('JsObject', function() { assert.equal((new Uint32Array(b))[3], 400100); }); + it('correctly writes to an empty ArrayBuffer using the borrow API', function() { + let nonempty = Uint8Array.from([1, 2, 3]); + addon.increment_array_buffer_with_borrow_mut(nonempty.buffer); + assert.deepEqual(Array.from(nonempty), [2, 3, 4]); + + let empty = Uint8Array.from([]); + addon.increment_array_buffer_with_borrow_mut(empty.buffer); + assert.deepEqual(Array.from(empty), []); + }); + it('gets a 16-byte, zeroed Buffer', function() { var b = addon.return_buffer(); assert.ok(b.equals(Buffer.alloc(16))); @@ -110,6 +128,14 @@ describe('JsObject', function() { assert.equal(addon.read_buffer_with_borrow(b, 3), 22914478); }); + it('correctly reads an empty Buffer using the borrow API', function() { + let nonempty = Buffer.from([1, 2, 3]); + assert.equal(addon.sum_buffer_with_borrow(nonempty), 6); + + let empty = Buffer.from([]); + assert.equal(addon.sum_buffer_with_borrow(empty), 0); + }); + it('correctly writes to a Buffer using the lock API', function() { var b = Buffer.allocUnsafe(16); b.fill(0); @@ -135,4 +161,14 @@ describe('JsObject', function() { addon.write_buffer_with_borrow_mut(b, 3, 66012); assert.equal(b.readUInt32LE(12), 66012); }); + + it('correctly writes to an empty Buffer using the borrow API', function() { + let nonempty = Buffer.from([1, 2, 3]); + addon.increment_buffer_with_borrow_mut(nonempty); + assert.deepEqual(Array.from(nonempty), [2, 3, 4]); + + let empty = Buffer.from([]); + addon.increment_buffer_with_borrow_mut(empty); + assert.deepEqual(Array.from(empty), []); + }); }); diff --git a/test/dynamic/native/src/js/objects.rs b/test/dynamic/native/src/js/objects.rs index 90672f25f..cdf6cfbfd 100644 --- a/test/dynamic/native/src/js/objects.rs +++ b/test/dynamic/native/src/js/objects.rs @@ -55,6 +55,12 @@ pub fn read_array_buffer_with_borrow(mut cx: FunctionContext) -> JsResult JsResult { + let b: Handle = cx.argument(0)?; + let x: u8 = cx.borrow(&b, |data| { data.as_slice::().iter().sum() }); + Ok(cx.number(x)) +} + pub fn write_array_buffer_with_lock(mut cx: FunctionContext) -> JsResult { let mut b: Handle = cx.argument(0)?; let i = cx.argument::(1)?.value() as u32 as usize; @@ -76,6 +82,12 @@ pub fn write_array_buffer_with_borrow_mut(mut cx: FunctionContext) -> JsResult JsResult { + let mut b: Handle = cx.argument(0)?; + cx.borrow_mut(&mut b, |data| { data.as_mut_slice::().iter_mut().for_each(|x| *x += 1); }); + Ok(cx.undefined()) +} + pub fn return_buffer(mut cx: FunctionContext) -> JsResult { let b: Handle = cx.buffer(16)?; Ok(b) @@ -100,6 +112,12 @@ pub fn read_buffer_with_borrow(mut cx: FunctionContext) -> JsResult { Ok(cx.number(x)) } +pub fn sum_buffer_with_borrow(mut cx: FunctionContext) -> JsResult { + let b: Handle = cx.argument(0)?; + let x: u8 = cx.borrow(&b, |data| { data.as_slice::().iter().sum() }); + Ok(cx.number(x)) +} + pub fn write_buffer_with_lock(mut cx: FunctionContext) -> JsResult { let mut b: Handle = cx.argument(0)?; let i = cx.argument::(1)?.value() as u32 as usize; @@ -120,3 +138,9 @@ pub fn write_buffer_with_borrow_mut(mut cx: FunctionContext) -> JsResult()[i] = x; }); Ok(cx.undefined()) } + +pub fn increment_buffer_with_borrow_mut(mut cx: FunctionContext) -> JsResult { + let mut b: Handle = cx.argument(0)?; + cx.borrow_mut(&mut b, |data| { data.as_mut_slice::().iter_mut().for_each(|x| *x += 1); }); + Ok(cx.undefined()) +} diff --git a/test/dynamic/native/src/lib.rs b/test/dynamic/native/src/lib.rs index 0a6291537..f12702c7e 100644 --- a/test/dynamic/native/src/lib.rs +++ b/test/dynamic/native/src/lib.rs @@ -46,13 +46,17 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> { cx.export_function("return_array_buffer", return_array_buffer)?; cx.export_function("read_array_buffer_with_lock", read_array_buffer_with_lock)?; cx.export_function("read_array_buffer_with_borrow", read_array_buffer_with_borrow)?; + cx.export_function("sum_array_buffer_with_borrow", sum_array_buffer_with_borrow)?; cx.export_function("write_array_buffer_with_lock", write_array_buffer_with_lock)?; cx.export_function("write_array_buffer_with_borrow_mut", write_array_buffer_with_borrow_mut)?; + cx.export_function("increment_array_buffer_with_borrow_mut", increment_array_buffer_with_borrow_mut)?; cx.export_function("return_buffer", return_buffer)?; cx.export_function("read_buffer_with_lock", read_buffer_with_lock)?; cx.export_function("read_buffer_with_borrow", read_buffer_with_borrow)?; + cx.export_function("sum_buffer_with_borrow", sum_buffer_with_borrow)?; cx.export_function("write_buffer_with_lock", write_buffer_with_lock)?; cx.export_function("write_buffer_with_borrow_mut", write_buffer_with_borrow_mut)?; + cx.export_function("increment_buffer_with_borrow_mut", increment_buffer_with_borrow_mut)?; cx.export_function("return_js_function", return_js_function)?; cx.export_function("call_js_function", call_js_function)?; diff --git a/test/napi/src/js/objects.rs b/test/napi/src/js/objects.rs index 9d10700f9..caf662f54 100644 --- a/test/napi/src/js/objects.rs +++ b/test/napi/src/js/objects.rs @@ -55,6 +55,12 @@ pub fn read_array_buffer_with_borrow(mut cx: FunctionContext) -> JsResult JsResult { + let b: Handle = cx.argument(0)?; + let x: u8 = cx.borrow(&b, |data| { data.as_slice::().iter().sum() }); + Ok(cx.number(x)) +} + pub fn write_array_buffer_with_lock(mut cx: FunctionContext) -> JsResult { let mut b: Handle = cx.argument(0)?; let i = cx.argument::(1)?.value(&mut cx) as u32 as usize; @@ -76,6 +82,12 @@ pub fn write_array_buffer_with_borrow_mut(mut cx: FunctionContext) -> JsResult JsResult { + let mut b: Handle = cx.argument(0)?; + cx.borrow_mut(&mut b, |data| { data.as_mut_slice::().iter_mut().for_each(|x| *x += 1); }); + Ok(cx.undefined()) +} + pub fn return_uninitialized_buffer(mut cx: FunctionContext) -> JsResult { let b: Handle = unsafe { JsBuffer::uninitialized(&mut cx, 16)? }; Ok(b) @@ -105,6 +117,12 @@ pub fn read_buffer_with_borrow(mut cx: FunctionContext) -> JsResult { Ok(cx.number(x)) } +pub fn sum_buffer_with_borrow(mut cx: FunctionContext) -> JsResult { + let b: Handle = cx.argument(0)?; + let x: u8 = cx.borrow(&b, |data| { data.as_slice::().iter().sum() }); + Ok(cx.number(x)) +} + pub fn write_buffer_with_lock(mut cx: FunctionContext) -> JsResult { let mut b: Handle = cx.argument(0)?; let i = cx.argument::(1)?.value(&mut cx) as u32 as usize; @@ -125,3 +143,9 @@ pub fn write_buffer_with_borrow_mut(mut cx: FunctionContext) -> JsResult()[i] = x; }); Ok(cx.undefined()) } + +pub fn increment_buffer_with_borrow_mut(mut cx: FunctionContext) -> JsResult { + let mut b: Handle = cx.argument(0)?; + cx.borrow_mut(&mut b, |data| { data.as_mut_slice::().iter_mut().for_each(|x| *x += 1); }); + Ok(cx.undefined()) +} diff --git a/test/napi/src/lib.rs b/test/napi/src/lib.rs index a25a8028e..bcfbc7c49 100644 --- a/test/napi/src/lib.rs +++ b/test/napi/src/lib.rs @@ -142,14 +142,18 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> { cx.export_function("return_array_buffer", return_array_buffer)?; cx.export_function("read_array_buffer_with_lock", read_array_buffer_with_lock)?; cx.export_function("read_array_buffer_with_borrow", read_array_buffer_with_borrow)?; + cx.export_function("sum_array_buffer_with_borrow", sum_array_buffer_with_borrow)?; cx.export_function("write_array_buffer_with_lock", write_array_buffer_with_lock)?; cx.export_function("write_array_buffer_with_borrow_mut", write_array_buffer_with_borrow_mut)?; + cx.export_function("increment_array_buffer_with_borrow_mut", increment_array_buffer_with_borrow_mut)?; cx.export_function("return_uninitialized_buffer", return_uninitialized_buffer)?; cx.export_function("return_buffer", return_buffer)?; cx.export_function("read_buffer_with_lock", read_buffer_with_lock)?; cx.export_function("read_buffer_with_borrow", read_buffer_with_borrow)?; + cx.export_function("sum_buffer_with_borrow", sum_buffer_with_borrow)?; cx.export_function("write_buffer_with_lock", write_buffer_with_lock)?; cx.export_function("write_buffer_with_borrow_mut", write_buffer_with_borrow_mut)?; + cx.export_function("increment_buffer_with_borrow_mut", increment_buffer_with_borrow_mut)?; cx.export_function("create_date", create_date)?; cx.export_function("get_date_value", get_date_value)?;