document BorrowChecker, make creation unsafe
This commit is contained in:
@@ -11,23 +11,36 @@ pub struct BorrowChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BorrowChecker {
|
impl BorrowChecker {
|
||||||
pub fn new() -> Self {
|
/// A `BorrowChecker` manages run-time validation of borrows from a `GuestMemory`. It keeps
|
||||||
|
/// track of regions of guest memory which are possible to alias with Rust references (via the
|
||||||
|
/// `GuestSlice` and `GuestStr` structs, which implement `std::ops::Deref` and
|
||||||
|
/// `std::ops::DerefMut`. It also enforces that `GuestPtr::read` and `GuestPtr::write` do not
|
||||||
|
/// access memory with an outstanding borrow.
|
||||||
|
/// The safety of this mechanism depends on creating exactly one `BorrowChecker` per
|
||||||
|
/// WebAssembly memory. There must be no other reads or writes of WebAssembly the memory by
|
||||||
|
/// either Rust or WebAssembly code while there are any outstanding borrows, as given by
|
||||||
|
/// `BorrowChecker::has_outstanding_borrows()`.
|
||||||
|
pub unsafe fn new() -> Self {
|
||||||
BorrowChecker {
|
BorrowChecker {
|
||||||
bc: RefCell::new(InnerBorrowChecker::new()),
|
bc: RefCell::new(InnerBorrowChecker::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn borrow(&self, r: Region) -> Result<BorrowHandle, GuestError> {
|
/// Indicates whether any outstanding borrows are known to the `BorrowChecker`. This function
|
||||||
|
/// must be `false` in order for it to be safe to recursively call into a WebAssembly module,
|
||||||
|
/// or to manipulate the WebAssembly memory by any other means.
|
||||||
|
pub fn has_outstanding_borrows(&self) -> bool {
|
||||||
|
self.bc.borrow().has_outstanding_borrows()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn borrow(&self, r: Region) -> Result<BorrowHandle, GuestError> {
|
||||||
self.bc.borrow_mut().borrow(r)
|
self.bc.borrow_mut().borrow(r)
|
||||||
}
|
}
|
||||||
pub fn unborrow(&self, h: BorrowHandle) {
|
pub(crate) fn unborrow(&self, h: BorrowHandle) {
|
||||||
self.bc.borrow_mut().unborrow(h)
|
self.bc.borrow_mut().unborrow(h)
|
||||||
}
|
}
|
||||||
pub fn is_borrowed(&self, r: Region) -> bool {
|
pub(crate) fn is_borrowed(&self, r: Region) -> bool {
|
||||||
self.bc.borrow().is_borrowed(r)
|
self.bc.borrow().is_borrowed(r)
|
||||||
}
|
}
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.bc.borrow().is_empty()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -44,8 +57,8 @@ impl InnerBorrowChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn has_outstanding_borrows(&self) -> bool {
|
||||||
self.borrows.is_empty()
|
!self.borrows.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_borrowed(&self, r: Region) -> bool {
|
fn is_borrowed(&self, r: Region) -> bool {
|
||||||
@@ -147,11 +160,20 @@ mod test {
|
|||||||
let r1 = Region::new(0, 10);
|
let r1 = Region::new(0, 10);
|
||||||
let r2 = Region::new(10, 10);
|
let r2 = Region::new(10, 10);
|
||||||
assert!(!r1.overlaps(r2));
|
assert!(!r1.overlaps(r2));
|
||||||
let _h1 = bs.borrow(r1).expect("can borrow r1");
|
assert_eq!(bs.has_outstanding_borrows(), false, "start with no borrows");
|
||||||
|
let h1 = bs.borrow(r1).expect("can borrow r1");
|
||||||
|
assert_eq!(bs.has_outstanding_borrows(), true, "h1 is outstanding");
|
||||||
let h2 = bs.borrow(r2).expect("can borrow r2");
|
let h2 = bs.borrow(r2).expect("can borrow r2");
|
||||||
|
|
||||||
assert!(bs.borrow(r2).is_err(), "can't borrow r2 twice");
|
assert!(bs.borrow(r2).is_err(), "can't borrow r2 twice");
|
||||||
bs.unborrow(h2);
|
bs.unborrow(h2);
|
||||||
|
assert_eq!(
|
||||||
|
bs.has_outstanding_borrows(),
|
||||||
|
true,
|
||||||
|
"h1 is still outstanding"
|
||||||
|
);
|
||||||
|
bs.unborrow(h1);
|
||||||
|
assert_eq!(bs.has_outstanding_borrows(), false, "no remaining borrows");
|
||||||
|
|
||||||
let _h3 = bs
|
let _h3 = bs
|
||||||
.borrow(r2)
|
.borrow(r2)
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ impl ReduceExcusesExcercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
// Populate memory with pointers to generated Excuse values
|
// Populate memory with pointers to generated Excuse values
|
||||||
for (&excuse, ptr) in self.excuse_values.iter().zip(self.excuse_ptr_locs.iter()) {
|
for (&excuse, ptr) in self.excuse_values.iter().zip(self.excuse_ptr_locs.iter()) {
|
||||||
@@ -169,7 +169,7 @@ impl PopulateExcusesExcercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
// Populate array with valid pointers to Excuse type in memory
|
// Populate array with valid pointers to Excuse type in memory
|
||||||
let ptr = host_memory.ptr::<[GuestPtr<'_, types::Excuse>]>(
|
let ptr = host_memory.ptr::<[GuestPtr<'_, types::Excuse>]>(
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ impl IntFloatExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
let e = atoms::int_float_args(&ctx, &host_memory, &bc, self.an_int as i32, self.an_float);
|
let e = atoms::int_float_args(&ctx, &host_memory, &bc, self.an_int as i32, self.an_float);
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ impl DoubleIntExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
let e = atoms::double_int_return_float(
|
let e = atoms::double_int_return_float(
|
||||||
&ctx,
|
&ctx,
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ impl ConfigureCarExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
// Populate input ptr
|
// Populate input ptr
|
||||||
host_memory
|
host_memory
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl HandleExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
let e = handle_examples::fd_create(&ctx, &host_memory, &bc, self.return_loc.ptr as i32);
|
let e = handle_examples::fd_create(&ctx, &host_memory, &bc, self.return_loc.ptr as i32);
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ impl CookieCutterExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
let res = ints::cookie_cutter(
|
let res = ints::cookie_cutter(
|
||||||
&ctx,
|
&ctx,
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ impl PointersAndEnumsExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(&bc, self.input2_loc.ptr)
|
.ptr(&bc, self.input2_loc.ptr)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ impl HelloStringExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
// Populate string in guest's memory
|
// Populate string in guest's memory
|
||||||
let ptr =
|
let ptr =
|
||||||
@@ -178,7 +178,7 @@ impl MultiStringExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
let write_string = |val: &str, loc: MemArea| {
|
let write_string = |val: &str, loc: MemArea| {
|
||||||
let ptr = host_memory.ptr::<str>(&bc, (loc.ptr, val.len() as u32));
|
let ptr = host_memory.ptr::<str>(&bc, (loc.ptr, val.len() as u32));
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ impl SumOfPairExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(&bc, self.input_loc.ptr)
|
.ptr(&bc, self.input_loc.ptr)
|
||||||
@@ -173,7 +173,7 @@ impl SumPairPtrsExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(&bc, self.input_first_loc.ptr)
|
.ptr(&bc, self.input_first_loc.ptr)
|
||||||
@@ -259,7 +259,7 @@ impl SumIntAndPtrExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(&bc, self.input_first_loc.ptr)
|
.ptr(&bc, self.input_first_loc.ptr)
|
||||||
@@ -318,7 +318,7 @@ impl ReturnPairInts {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
let err = structs::return_pair_ints(&ctx, &host_memory, &bc, self.return_loc.ptr as i32);
|
let err = structs::return_pair_ints(&ctx, &host_memory, &bc, self.return_loc.ptr as i32);
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@ impl ReturnPairPtrsExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
host_memory
|
host_memory
|
||||||
.ptr(&bc, self.input_first_loc.ptr)
|
.ptr(&bc, self.input_first_loc.ptr)
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ impl GetTagExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
let discriminant: u8 = reason_tag(&self.input).into();
|
let discriminant: u8 = reason_tag(&self.input).into();
|
||||||
host_memory
|
host_memory
|
||||||
@@ -186,7 +186,7 @@ impl ReasonMultExercise {
|
|||||||
pub fn test(&self) {
|
pub fn test(&self) {
|
||||||
let ctx = WasiCtx::new();
|
let ctx = WasiCtx::new();
|
||||||
let host_memory = HostMemory::new();
|
let host_memory = HostMemory::new();
|
||||||
let bc = BorrowChecker::new();
|
let bc = unsafe { BorrowChecker::new() };
|
||||||
|
|
||||||
let discriminant: u8 = reason_tag(&self.input).into();
|
let discriminant: u8 = reason_tag(&self.input).into();
|
||||||
host_memory
|
host_memory
|
||||||
|
|||||||
Reference in New Issue
Block a user