diff --git a/crates/wiggle/borrow/src/lib.rs b/crates/wiggle/borrow/src/lib.rs index 288c50f931..086f350d2e 100644 --- a/crates/wiggle/borrow/src/lib.rs +++ b/crates/wiggle/borrow/src/lib.rs @@ -31,11 +31,17 @@ impl BorrowChecker { pub fn mut_borrow(&self, r: Region) -> Result { self.bc.borrow_mut().mut_borrow(r) } - pub fn unborrow(&self, h: BorrowHandle) { - self.bc.borrow_mut().unborrow(h) + pub fn shared_unborrow(&self, h: BorrowHandle) { + self.bc.borrow_mut().shared_unborrow(h) } - pub fn is_borrowed(&self, r: Region) -> bool { - self.bc.borrow().is_borrowed(r) + pub fn mut_unborrow(&self, h: BorrowHandle) { + self.bc.borrow_mut().mut_unborrow(h) + } + pub fn is_shared_borrowed(&self, r: Region) -> bool { + self.bc.borrow().is_shared_borrowed(r) + } + pub fn is_mut_borrowed(&self, r: Region) -> bool { + self.bc.borrow().is_mut_borrowed(r) } } @@ -68,12 +74,11 @@ impl InnerBorrowChecker { !(self.shared_borrows.is_empty() && self.mut_borrows.is_empty()) } - fn is_borrowed(&self, r: Region) -> bool { - !self - .shared_borrows - .values() - .chain(self.mut_borrows.values()) - .all(|b| !b.overlaps(r)) + fn is_shared_borrowed(&self, r: Region) -> bool { + self.shared_borrows.values().any(|b| b.overlaps(r)) + } + fn is_mut_borrowed(&self, r: Region) -> bool { + self.mut_borrows.values().any(|b| b.overlaps(r)) } fn new_handle(&mut self) -> Result { @@ -95,7 +100,7 @@ impl InnerBorrowChecker { } fn shared_borrow(&mut self, r: Region) -> Result { - if !self.mut_borrows.values().all(|b| !b.overlaps(r)) { + if self.is_mut_borrowed(r) { return Err(GuestError::PtrBorrowed(r)); } let h = self.new_handle()?; @@ -104,7 +109,7 @@ impl InnerBorrowChecker { } fn mut_borrow(&mut self, r: Region) -> Result { - if self.is_borrowed(r) { + if self.is_shared_borrowed(r) || self.is_mut_borrowed(r) { return Err(GuestError::PtrBorrowed(r)); } let h = self.new_handle()?; @@ -112,11 +117,12 @@ impl InnerBorrowChecker { Ok(h) } - fn unborrow(&mut self, h: BorrowHandle) { - let removed = self.mut_borrows.remove(&h); - if removed.is_none() { - let _ = self.shared_borrows.remove(&h); - } + fn shared_unborrow(&mut self, h: BorrowHandle) { + let _ = self.shared_borrows.remove(&h); + } + + fn mut_unborrow(&mut self, h: BorrowHandle) { + let _ = self.mut_borrows.remove(&h); } } diff --git a/crates/wiggle/src/guest_type.rs b/crates/wiggle/src/guest_type.rs index 422c3f2394..0fae52491e 100644 --- a/crates/wiggle/src/guest_type.rs +++ b/crates/wiggle/src/guest_type.rs @@ -85,7 +85,7 @@ macro_rules! primitives { start: offset, len: size, }; - if ptr.mem().is_borrowed(region) { + if ptr.mem().is_mut_borrowed(region) { return Err(GuestError::PtrBorrowed(region)); } Ok(unsafe { <$i>::from_le_bytes(*host_ptr.cast::<[u8; mem::size_of::()]>()) }) @@ -104,7 +104,7 @@ macro_rules! primitives { start: offset, len: size, }; - if ptr.mem().is_borrowed(region) { + if ptr.mem().is_shared_borrowed(region) || ptr.mem().is_mut_borrowed(region) { return Err(GuestError::PtrBorrowed(region)); } unsafe { diff --git a/crates/wiggle/src/lib.rs b/crates/wiggle/src/lib.rs index 497fec4a7a..063ab5bd4b 100644 --- a/crates/wiggle/src/lib.rs +++ b/crates/wiggle/src/lib.rs @@ -153,28 +153,36 @@ pub unsafe trait GuestMemory { /// safe to recursively call into a WebAssembly module, or to manipulate /// the WebAssembly memory by any other means. fn has_outstanding_borrows(&self) -> bool; - /// Check if a region of linear memory is borrowed. This is called during - /// any `GuestPtr::read` or `GuestPtr::write` operation to ensure that - /// wiggle is not reading or writing a region of memory which Rust believes - /// it has exclusive access to. - fn is_borrowed(&self, r: Region) -> bool; - /// Borrow a region of linear memory. This is used when constructing a - /// `GuestSlice` or `GuestStr`. Those types will give Rust `&mut` access + /// Check if a region of linear memory is exclusively borrowed. This is called during any + /// `GuestPtr::read` or `GuestPtr::write` operation to ensure that wiggle is not reading or + /// writing a region of memory which Rust believes it has exclusive access to. + fn is_mut_borrowed(&self, r: Region) -> bool; + /// Check if a region of linear memory has any shared borrows. + fn is_shared_borrowed(&self, r: Region) -> bool; + /// Exclusively borrow a region of linear memory. This is used when constructing a + /// `GuestSliceMut` or `GuestStrMut`. Those types will give Rust `&mut` access /// to the region of linear memory, therefore, the `GuestMemory` impl must /// guarantee that at most one `BorrowHandle` is issued to a given region, /// `GuestMemory::has_outstanding_borrows` is true for the duration of the - /// borrow, and that `GuestMemory::is_borrowed` of any overlapping region + /// borrow, and that `GuestMemory::is_mut_borrowed` of any overlapping region /// is false for the duration of the borrow. fn mut_borrow(&self, r: Region) -> Result; + /// Shared borrow a region of linear memory. This is used when constructing a + /// `GuestSlice` or `GuestStr`. Those types will give Rust `&` (shared reference) access + /// to the region of linear memory. fn shared_borrow(&self, r: Region) -> Result; - /// Unborrow a previously borrowed region. As long as `GuestSlice` and - /// `GuestStr` are implemented correctly, a `BorrowHandle` should only be + /// Unborrow a previously borrowed mutable region. As long as `GuestSliceMut` and + /// `GuestStrMut` are implemented correctly, a mut `BorrowHandle` should only be /// unborrowed once. - fn unborrow(&self, h: BorrowHandle); + fn mut_unborrow(&self, h: BorrowHandle); + /// Unborrow a previously borrowed shared region. As long as `GuestSlice` and + /// `GuestStr` are implemented correctly, a shared `BorrowHandle` should only be + /// unborrowed once. + fn shared_unborrow(&self, h: BorrowHandle); } -/// A handle to a borrow on linear memory. It is produced by `borrow` and -/// consumed by `unborrow`. Only the `GuestMemory` impl should ever construct +/// A handle to a borrow on linear memory. It is produced by `{mut, shared}_borrow` and +/// consumed by `{mut, shared}_unborrow`. Only the `GuestMemory` impl should ever construct /// a `BorrowHandle` or inspect its contents. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct BorrowHandle(pub usize); @@ -187,8 +195,11 @@ unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a T { fn has_outstanding_borrows(&self) -> bool { T::has_outstanding_borrows(self) } - fn is_borrowed(&self, r: Region) -> bool { - T::is_borrowed(self, r) + fn is_mut_borrowed(&self, r: Region) -> bool { + T::is_mut_borrowed(self, r) + } + fn is_shared_borrowed(&self, r: Region) -> bool { + T::is_shared_borrowed(self, r) } fn mut_borrow(&self, r: Region) -> Result { T::mut_borrow(self, r) @@ -196,8 +207,11 @@ unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a T { fn shared_borrow(&self, r: Region) -> Result { T::shared_borrow(self, r) } - fn unborrow(&self, h: BorrowHandle) { - T::unborrow(self, h) + fn mut_unborrow(&self, h: BorrowHandle) { + T::mut_unborrow(self, h) + } + fn shared_unborrow(&self, h: BorrowHandle) { + T::shared_unborrow(self, h) } } @@ -208,8 +222,11 @@ unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a mut T { fn has_outstanding_borrows(&self) -> bool { T::has_outstanding_borrows(self) } - fn is_borrowed(&self, r: Region) -> bool { - T::is_borrowed(self, r) + fn is_mut_borrowed(&self, r: Region) -> bool { + T::is_mut_borrowed(self, r) + } + fn is_shared_borrowed(&self, r: Region) -> bool { + T::is_shared_borrowed(self, r) } fn mut_borrow(&self, r: Region) -> Result { T::mut_borrow(self, r) @@ -217,8 +234,11 @@ unsafe impl<'a, T: ?Sized + GuestMemory> GuestMemory for &'a mut T { fn shared_borrow(&self, r: Region) -> Result { T::shared_borrow(self, r) } - fn unborrow(&self, h: BorrowHandle) { - T::unborrow(self, h) + fn mut_unborrow(&self, h: BorrowHandle) { + T::mut_unborrow(self, h) + } + fn shared_unborrow(&self, h: BorrowHandle) { + T::shared_unborrow(self, h) } } @@ -229,8 +249,11 @@ unsafe impl GuestMemory for Box { fn has_outstanding_borrows(&self) -> bool { T::has_outstanding_borrows(self) } - fn is_borrowed(&self, r: Region) -> bool { - T::is_borrowed(self, r) + fn is_mut_borrowed(&self, r: Region) -> bool { + T::is_mut_borrowed(self, r) + } + fn is_shared_borrowed(&self, r: Region) -> bool { + T::is_shared_borrowed(self, r) } fn mut_borrow(&self, r: Region) -> Result { T::mut_borrow(self, r) @@ -238,8 +261,11 @@ unsafe impl GuestMemory for Box { fn shared_borrow(&self, r: Region) -> Result { T::shared_borrow(self, r) } - fn unborrow(&self, h: BorrowHandle) { - T::unborrow(self, h) + fn mut_unborrow(&self, h: BorrowHandle) { + T::mut_unborrow(self, h) + } + fn shared_unborrow(&self, h: BorrowHandle) { + T::shared_unborrow(self, h) } } @@ -250,8 +276,11 @@ unsafe impl GuestMemory for Rc { fn has_outstanding_borrows(&self) -> bool { T::has_outstanding_borrows(self) } - fn is_borrowed(&self, r: Region) -> bool { - T::is_borrowed(self, r) + fn is_mut_borrowed(&self, r: Region) -> bool { + T::is_mut_borrowed(self, r) + } + fn is_shared_borrowed(&self, r: Region) -> bool { + T::is_shared_borrowed(self, r) } fn mut_borrow(&self, r: Region) -> Result { T::mut_borrow(self, r) @@ -259,8 +288,11 @@ unsafe impl GuestMemory for Rc { fn shared_borrow(&self, r: Region) -> Result { T::shared_borrow(self, r) } - fn unborrow(&self, h: BorrowHandle) { - T::unborrow(self, h) + fn mut_unborrow(&self, h: BorrowHandle) { + T::mut_unborrow(self, h) + } + fn shared_unborrow(&self, h: BorrowHandle) { + T::shared_unborrow(self, h) } } @@ -271,8 +303,11 @@ unsafe impl GuestMemory for Arc { fn has_outstanding_borrows(&self) -> bool { T::has_outstanding_borrows(self) } - fn is_borrowed(&self, r: Region) -> bool { - T::is_borrowed(self, r) + fn is_mut_borrowed(&self, r: Region) -> bool { + T::is_mut_borrowed(self, r) + } + fn is_shared_borrowed(&self, r: Region) -> bool { + T::is_shared_borrowed(self, r) } fn mut_borrow(&self, r: Region) -> Result { T::mut_borrow(self, r) @@ -280,8 +315,11 @@ unsafe impl GuestMemory for Arc { fn shared_borrow(&self, r: Region) -> Result { T::shared_borrow(self, r) } - fn unborrow(&self, h: BorrowHandle) { - T::unborrow(self, h) + fn mut_unborrow(&self, h: BorrowHandle) { + T::mut_unborrow(self, h) + } + fn shared_unborrow(&self, h: BorrowHandle) { + T::shared_unborrow(self, h) } } @@ -771,7 +809,7 @@ impl<'a, T> std::ops::Deref for GuestSlice<'a, T> { impl<'a, T> Drop for GuestSlice<'a, T> { fn drop(&mut self) { - self.mem.unborrow(self.borrow) + self.mem.shared_unborrow(self.borrow) } } @@ -799,7 +837,7 @@ impl<'a, T> std::ops::DerefMut for GuestSliceMut<'a, T> { impl<'a, T> Drop for GuestSliceMut<'a, T> { fn drop(&mut self) { - self.mem.unborrow(self.borrow) + self.mem.mut_unborrow(self.borrow) } } @@ -820,7 +858,7 @@ impl<'a> std::ops::Deref for GuestStr<'a> { impl<'a> Drop for GuestStr<'a> { fn drop(&mut self) { - self.mem.unborrow(self.borrow) + self.mem.shared_unborrow(self.borrow) } } @@ -848,7 +886,7 @@ impl<'a> std::ops::DerefMut for GuestStrMut<'a> { impl<'a> Drop for GuestStrMut<'a> { fn drop(&mut self) { - self.mem.unborrow(self.borrow) + self.mem.mut_unborrow(self.borrow) } } diff --git a/crates/wiggle/test-helpers/src/lib.rs b/crates/wiggle/test-helpers/src/lib.rs index 7ba2d5a6e4..99571367a5 100644 --- a/crates/wiggle/test-helpers/src/lib.rs +++ b/crates/wiggle/test-helpers/src/lib.rs @@ -125,8 +125,11 @@ unsafe impl GuestMemory for HostMemory { fn has_outstanding_borrows(&self) -> bool { self.bc.has_outstanding_borrows() } - fn is_borrowed(&self, r: Region) -> bool { - self.bc.is_borrowed(r) + fn is_shared_borrowed(&self, r: Region) -> bool { + self.bc.is_shared_borrowed(r) + } + fn is_mut_borrowed(&self, r: Region) -> bool { + self.bc.is_mut_borrowed(r) } fn mut_borrow(&self, r: Region) -> Result { self.bc.mut_borrow(r) @@ -134,8 +137,11 @@ unsafe impl GuestMemory for HostMemory { fn shared_borrow(&self, r: Region) -> Result { self.bc.shared_borrow(r) } - fn unborrow(&self, h: BorrowHandle) { - self.bc.unborrow(h) + fn shared_unborrow(&self, h: BorrowHandle) { + self.bc.shared_unborrow(h) + } + fn mut_unborrow(&self, h: BorrowHandle) { + self.bc.mut_unborrow(h) } } diff --git a/crates/wiggle/wasmtime/src/lib.rs b/crates/wiggle/wasmtime/src/lib.rs index b102d874ba..dc43683c14 100644 --- a/crates/wiggle/wasmtime/src/lib.rs +++ b/crates/wiggle/wasmtime/src/lib.rs @@ -35,8 +35,11 @@ unsafe impl GuestMemory for WasmtimeGuestMemory { fn has_outstanding_borrows(&self) -> bool { self.bc.has_outstanding_borrows() } - fn is_borrowed(&self, r: Region) -> bool { - self.bc.is_borrowed(r) + fn is_shared_borrowed(&self, r: Region) -> bool { + self.bc.is_shared_borrowed(r) + } + fn is_mut_borrowed(&self, r: Region) -> bool { + self.bc.is_mut_borrowed(r) } fn shared_borrow(&self, r: Region) -> Result { self.bc.shared_borrow(r) @@ -44,7 +47,10 @@ unsafe impl GuestMemory for WasmtimeGuestMemory { fn mut_borrow(&self, r: Region) -> Result { self.bc.mut_borrow(r) } - fn unborrow(&self, h: BorrowHandle) { - self.bc.unborrow(h) + fn shared_unborrow(&self, h: BorrowHandle) { + self.bc.shared_unborrow(h) + } + fn mut_unborrow(&self, h: BorrowHandle) { + self.bc.mut_unborrow(h) } }