borrow checker: reset index when empty, handle oom

This commit is contained in:
Pat Hickey
2020-05-18 18:56:30 -07:00
parent 52e8300f01
commit 73602c6bfe
2 changed files with 23 additions and 17 deletions

View File

@@ -17,10 +17,7 @@ impl BorrowChecker {
} }
} }
pub fn borrow(&self, r: Region) -> Result<BorrowHandle, GuestError> { pub fn borrow(&self, r: Region) -> Result<BorrowHandle, GuestError> {
self.bc self.bc.borrow_mut().borrow(r)
.borrow_mut()
.borrow(r)
.ok_or_else(|| GuestError::PtrBorrowed(r))
} }
pub fn unborrow(&self, h: BorrowHandle) { pub fn unborrow(&self, h: BorrowHandle) {
self.bc.borrow_mut().unborrow(h) self.bc.borrow_mut().unborrow(h)
@@ -45,19 +42,26 @@ impl InnerBorrowChecker {
!self.borrows.values().all(|b| !b.overlaps(r)) !self.borrows.values().all(|b| !b.overlaps(r))
} }
fn new_handle(&mut self) -> BorrowHandle { fn new_handle(&mut self) -> Result<BorrowHandle, GuestError> {
// Reset handles to 0 if all handles have been returned.
if self.borrows.is_empty() {
self.next_handle = BorrowHandle(0);
}
let h = self.next_handle; let h = self.next_handle;
self.next_handle = BorrowHandle(h.0 + 1); self.next_handle = BorrowHandle(
h h.0.checked_add(1)
.ok_or_else(|| GuestError::BorrowCheckerOOM)?,
);
Ok(h)
} }
fn borrow(&mut self, r: Region) -> Option<BorrowHandle> { fn borrow(&mut self, r: Region) -> Result<BorrowHandle, GuestError> {
if self.is_borrowed(r) { if self.is_borrowed(r) {
return None; return Err(GuestError::PtrBorrowed(r));
} }
let h = self.new_handle(); let h = self.new_handle()?;
self.borrows.insert(h, r); self.borrows.insert(h, r);
Some(h) Ok(h)
} }
fn unborrow(&mut self, h: BorrowHandle) { fn unborrow(&mut self, h: BorrowHandle) {
@@ -92,28 +96,28 @@ mod test {
let r2 = Region::new(9, 10); let r2 = Region::new(9, 10);
assert!(r1.overlaps(r2)); assert!(r1.overlaps(r2));
bs.borrow(r1).expect("can borrow r1"); bs.borrow(r1).expect("can borrow r1");
assert!(bs.borrow(r2).is_none(), "cant borrow r2"); assert!(bs.borrow(r2).is_err(), "cant borrow r2");
let mut bs = InnerBorrowChecker::new(); let mut bs = InnerBorrowChecker::new();
let r1 = Region::new(0, 10); let r1 = Region::new(0, 10);
let r2 = Region::new(2, 5); let r2 = Region::new(2, 5);
assert!(r1.overlaps(r2)); assert!(r1.overlaps(r2));
bs.borrow(r1).expect("can borrow r1"); bs.borrow(r1).expect("can borrow r1");
assert!(bs.borrow(r2).is_none(), "cant borrow r2"); assert!(bs.borrow(r2).is_err(), "cant borrow r2");
let mut bs = InnerBorrowChecker::new(); let mut bs = InnerBorrowChecker::new();
let r1 = Region::new(9, 10); let r1 = Region::new(9, 10);
let r2 = Region::new(0, 10); let r2 = Region::new(0, 10);
assert!(r1.overlaps(r2)); assert!(r1.overlaps(r2));
bs.borrow(r1).expect("can borrow r1"); bs.borrow(r1).expect("can borrow r1");
assert!(bs.borrow(r2).is_none(), "cant borrow r2"); assert!(bs.borrow(r2).is_err(), "cant borrow r2");
let mut bs = InnerBorrowChecker::new(); let mut bs = InnerBorrowChecker::new();
let r1 = Region::new(2, 5); let r1 = Region::new(2, 5);
let r2 = Region::new(0, 10); let r2 = Region::new(0, 10);
assert!(r1.overlaps(r2)); assert!(r1.overlaps(r2));
bs.borrow(r1).expect("can borrow r1"); bs.borrow(r1).expect("can borrow r1");
assert!(bs.borrow(r2).is_none(), "cant borrow r2"); assert!(bs.borrow(r2).is_err(), "cant borrow r2");
let mut bs = InnerBorrowChecker::new(); let mut bs = InnerBorrowChecker::new();
let r1 = Region::new(2, 5); let r1 = Region::new(2, 5);
@@ -124,7 +128,7 @@ mod test {
bs.borrow(r1).expect("can borrow r1"); bs.borrow(r1).expect("can borrow r1");
bs.borrow(r2).expect("can borrow r2"); bs.borrow(r2).expect("can borrow r2");
bs.borrow(r3).expect("can borrow r3"); bs.borrow(r3).expect("can borrow r3");
assert!(bs.borrow(r4).is_none(), "cant borrow r4"); assert!(bs.borrow(r4).is_err(), "cant borrow r4");
} }
#[test] #[test]
@@ -136,7 +140,7 @@ mod test {
let _h1 = bs.borrow(r1).expect("can borrow r1"); let _h1 = bs.borrow(r1).expect("can borrow r1");
let h2 = bs.borrow(r2).expect("can borrow r2"); let h2 = bs.borrow(r2).expect("can borrow r2");
assert!(bs.borrow(r2).is_none(), "can't borrow r2 twice"); assert!(bs.borrow(r2).is_err(), "can't borrow r2 twice");
bs.unborrow(h2); bs.unborrow(h2);
let _h3 = bs let _h3 = bs

View File

@@ -15,6 +15,8 @@ pub enum GuestError {
PtrNotAligned(Region, u32), PtrNotAligned(Region, u32),
#[error("Pointer already borrowed: {0:?}")] #[error("Pointer already borrowed: {0:?}")]
PtrBorrowed(Region), PtrBorrowed(Region),
#[error("Borrow checker out of memory")]
BorrowCheckerOOM,
#[error("Slice length mismatch")] #[error("Slice length mismatch")]
SliceLengthsDiffer, SliceLengthsDiffer,
#[error("In func {funcname}:{location}:")] #[error("In func {funcname}:{location}:")]