From 1fae2ed61bcb99d28a9840a8fc7d99d7ba09c366 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 23 Jun 2021 22:51:47 -0700 Subject: [PATCH] Make all tests pass --- lib/js-api/src/ptr.rs | 162 ++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 92 deletions(-) diff --git a/lib/js-api/src/ptr.rs b/lib/js-api/src/ptr.rs index 0daec98c4..77e98bea0 100644 --- a/lib/js-api/src/ptr.rs +++ b/lib/js-api/src/ptr.rs @@ -155,24 +155,32 @@ impl WasmPtr { /// If you're unsure what that means, it likely does not apply to you. /// This invariant will be enforced in the future. #[inline] - pub fn deref(self, memory: &Memory, index: u32, length: u32) -> Option<&[Cell]> { + pub fn deref(self, memory: &Memory, index: u32, length: u32) -> Option]>> { // gets the size of the item in the array with padding added such that // for any index, we will always result an aligned memory access - let item_size = mem::size_of::(); - let slice_full_len = index as usize + length as usize; - let memory_size = memory.size().bytes().0; + let item_size = mem::size_of::() as u32; + let slice_full_len = index + length; + let memory_size = memory.size().bytes().0 as u32; - if (self.offset as usize) + (item_size * slice_full_len) > memory_size - || self.offset as usize >= memory_size - || mem::size_of::() == 0 + if self.offset + (item_size * slice_full_len) > memory_size + || self.offset >= memory_size + || item_size == 0 { return None; } - // let subarray = &memory.uint8view().subarray(self.offset, total_len as u32); - // let subarray_static = unsafe { std::mem::transmute::<&js_sys::Uint8Array, &'static js_sys::Uint8Array>(&subarray) }; - // Some(WasmCell::new(subarray_static)) - unimplemented!(); + Some( + (0..length) + .map(|i| { + let subarray = memory.uint8view().subarray( + self.offset + i * item_size, + self.offset + (i + 1) * item_size, + ); + WasmCell::new(subarray) + }) + .collect::>() + .into_boxed_slice(), + ) // unsafe { // let cell_ptr = align_pointer( // memory.view::().as_ptr().add(self.offset as usize) as usize, @@ -197,8 +205,8 @@ impl WasmPtr { memory: &Memory, index: u32, length: u32, - ) -> Option<&mut [Cell]> { - unimplemented!(); + ) -> Option]>> { + self.deref(memory, index, length) // // gets the size of the item in the array with padding added such that // // for any index, we will always result an aligned memory access // let item_size = mem::size_of::(); @@ -238,7 +246,11 @@ impl WasmPtr { /// /// Additionally, if `memory` is dynamic, the caller must also ensure that `memory` /// is not grown while the reference is held. - pub unsafe fn get_utf8_str<'a>(self, memory: &'a Memory, str_len: u32) -> Option<&'a str> { + pub unsafe fn get_utf8_str<'a>( + self, + memory: &'a Memory, + str_len: u32, + ) -> Option> { let memory_size = memory.size().bytes().0; if self.offset as usize + str_len as usize > memory.size().bytes().0 @@ -246,9 +258,9 @@ impl WasmPtr { { return None; } - let ptr = memory.view::().as_ptr().add(self.offset as usize) as *const u8; - let slice: &[u8] = std::slice::from_raw_parts(ptr, str_len as usize); - std::str::from_utf8(slice).ok() + let subarray = memory.uint8view().subarray(self.offset, str_len).to_vec(); + // std::str::from_utf8(subarray.as_slice()).ok() + String::from_utf8(subarray).ok().map(std::borrow::Cow::from) } /// Get a UTF-8 `String` from the `WasmPtr` with the given length. @@ -262,42 +274,8 @@ impl WasmPtr { return None; } - // TODO: benchmark the internals of this function: there is likely room for - // micro-optimization here and this may be a fairly common function in user code. - let view = memory.view::(); - - let mut vec: Vec = Vec::with_capacity(str_len as usize); - let base = self.offset as usize; - for i in 0..(str_len as usize) { - let byte = view[base + i].get(); - vec.push(byte); - } - - String::from_utf8(vec).ok() - } - - /// Get a UTF-8 string from the `WasmPtr`, where the string is nul-terminated. - /// - /// Note that this does not account for UTF-8 strings that _contain_ nul themselves, - /// [`WasmPtr::get_utf8_str`] has to be used for those. - /// - /// # Safety - /// This method behaves similarly to [`WasmPtr::get_utf8_str`], all safety invariants on - /// that method must also be upheld here. - pub unsafe fn get_utf8_str_with_nul<'a>(self, memory: &'a Memory) -> Option<&'a str> { - memory.view::()[(self.offset as usize)..] - .iter() - .map(|cell| cell.get()) - .position(|byte| byte == 0) - .and_then(|length| self.get_utf8_str(memory, length as u32)) - } - - /// Get a UTF-8 `String` from the `WasmPtr`, where the string is nul-terminated. - /// - /// Note that this does not account for UTF-8 strings that _contain_ nul themselves, - /// [`WasmPtr::get_utf8_string`] has to be used for those. - pub fn get_utf8_string_with_nul(self, memory: &Memory) -> Option { - unsafe { self.get_utf8_str_with_nul(memory) }.map(|s| s.to_owned()) + let subarray = memory.uint8view().subarray(self.offset, str_len).to_vec(); + String::from_utf8(subarray).ok() } } @@ -386,16 +364,16 @@ mod test { // test that basic access works and that len = 0 works, but oob does not let start_wasm_ptr: WasmPtr = WasmPtr::new(0); - // let start_wasm_ptr_array: WasmPtr = WasmPtr::new(0); + let start_wasm_ptr_array: WasmPtr = WasmPtr::new(0); assert!(start_wasm_ptr.deref(&memory).is_some()); assert!(unsafe { start_wasm_ptr.deref_mut(&memory).is_some() }); - // assert!(start_wasm_ptr_array.deref(&memory, 0, 0).is_some()); - // assert!(unsafe { start_wasm_ptr_array.get_utf8_str(&memory, 0).is_some() }); - // assert!(start_wasm_ptr_array.get_utf8_string(&memory, 0).is_some()); - // assert!(unsafe { start_wasm_ptr_array.deref_mut(&memory, 0, 0).is_some() }); - // assert!(start_wasm_ptr_array.deref(&memory, 0, 1).is_some()); - // assert!(unsafe { start_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() }); + assert!(start_wasm_ptr_array.deref(&memory, 0, 0).is_some()); + assert!(unsafe { start_wasm_ptr_array.get_utf8_str(&memory, 0).is_some() }); + assert!(start_wasm_ptr_array.get_utf8_string(&memory, 0).is_some()); + assert!(unsafe { start_wasm_ptr_array.deref_mut(&memory, 0, 0).is_some() }); + assert!(start_wasm_ptr_array.deref(&memory, 0, 1).is_some()); + assert!(unsafe { start_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() }); // test that accessing the last valid memory address works correctly and OOB is caught let last_valid_address_for_u8 = (memory.size().bytes().0 - 1) as u32; @@ -403,18 +381,18 @@ mod test { assert!(end_wasm_ptr.deref(&memory).is_some()); assert!(unsafe { end_wasm_ptr.deref_mut(&memory).is_some() }); - // let end_wasm_ptr_array: WasmPtr = WasmPtr::new(last_valid_address_for_u8); + let end_wasm_ptr_array: WasmPtr = WasmPtr::new(last_valid_address_for_u8); - // assert!(end_wasm_ptr_array.deref(&memory, 0, 1).is_some()); - // assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() }); - // let invalid_idx_len_combos: [(u32, u32); 3] = - // [(last_valid_address_for_u8 + 1, 0), (0, 2), (1, 1)]; - // for &(idx, len) in invalid_idx_len_combos.iter() { - // assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none()); - // assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, idx, len).is_none() }); - // } - // assert!(unsafe { end_wasm_ptr_array.get_utf8_str(&memory, 2).is_none() }); - // assert!(end_wasm_ptr_array.get_utf8_string(&memory, 2).is_none()); + assert!(end_wasm_ptr_array.deref(&memory, 0, 1).is_some()); + assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() }); + let invalid_idx_len_combos: [(u32, u32); 3] = + [(last_valid_address_for_u8 + 1, 0), (0, 2), (1, 1)]; + for &(idx, len) in invalid_idx_len_combos.iter() { + assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none()); + assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, idx, len).is_none() }); + } + assert!(unsafe { end_wasm_ptr_array.get_utf8_str(&memory, 2).is_none() }); + assert!(end_wasm_ptr_array.get_utf8_string(&memory, 2).is_none()); // test that accesing the last valid memory address for a u32 is valid // (same as above test but with more edge cases to assert on) @@ -435,29 +413,29 @@ mod test { assert!(oob_end_ptr.deref(&memory).is_none()); assert!(unsafe { oob_end_ptr.deref_mut(&memory).is_none() }); } - // let end_wasm_ptr_array: WasmPtr = WasmPtr::new(last_valid_address_for_u32); - // assert!(end_wasm_ptr_array.deref(&memory, 0, 1).is_some()); - // assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() }); + let end_wasm_ptr_array: WasmPtr = WasmPtr::new(last_valid_address_for_u32); + assert!(end_wasm_ptr_array.deref(&memory, 0, 1).is_some()); + assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() }); - // let invalid_idx_len_combos: [(u32, u32); 3] = - // [(last_valid_address_for_u32 + 1, 0), (0, 2), (1, 1)]; - // for &(idx, len) in invalid_idx_len_combos.iter() { - // assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none()); - // assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, idx, len).is_none() }); - // } + let invalid_idx_len_combos: [(u32, u32); 3] = + [(last_valid_address_for_u32 + 1, 0), (0, 2), (1, 1)]; + for &(idx, len) in invalid_idx_len_combos.iter() { + assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none()); + assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, idx, len).is_none() }); + } - // let end_wasm_ptr_array_oob_array: [WasmPtr; 4] = [ - // WasmPtr::new(last_valid_address_for_u32 + 1), - // WasmPtr::new(last_valid_address_for_u32 + 2), - // WasmPtr::new(last_valid_address_for_u32 + 3), - // WasmPtr::new(last_valid_address_for_u32 + 4), - // ]; + let end_wasm_ptr_array_oob_array: [WasmPtr; 4] = [ + WasmPtr::new(last_valid_address_for_u32 + 1), + WasmPtr::new(last_valid_address_for_u32 + 2), + WasmPtr::new(last_valid_address_for_u32 + 3), + WasmPtr::new(last_valid_address_for_u32 + 4), + ]; - // for oob_end_array_ptr in end_wasm_ptr_array_oob_array.iter() { - // assert!(oob_end_array_ptr.deref(&memory, 0, 1).is_none()); - // assert!(unsafe { oob_end_array_ptr.deref_mut(&memory, 0, 1).is_none() }); - // assert!(oob_end_array_ptr.deref(&memory, 1, 0).is_none()); - // assert!(unsafe { oob_end_array_ptr.deref_mut(&memory, 1, 0).is_none() }); - // } + for oob_end_array_ptr in end_wasm_ptr_array_oob_array.iter() { + assert!(oob_end_array_ptr.deref(&memory, 0, 1).is_none()); + assert!(unsafe { oob_end_array_ptr.deref_mut(&memory, 0, 1).is_none() }); + assert!(oob_end_array_ptr.deref(&memory, 1, 0).is_none()); + assert!(unsafe { oob_end_array_ptr.deref_mut(&memory, 1, 0).is_none() }); + } } }