diff --git a/src/lib.rs b/src/lib.rs index 46b9828c185d081a60cb0d45a29d713a2e1fb868..f76cb79008c278bb0ed7343ec0c9529e4042f349 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,6 +135,7 @@ pub struct Unclaimed<T> { impl<T> Unclaimed<T> { pub fn claim(self, value: T) -> Xrc<T> { unsafe { + debug_assert_eq!((*self.ptr.as_ptr()).state.get(), STATE_UNCLAIMED); (*self.ptr.as_ptr()).state.set(STATE_SHARED_INIT); } @@ -163,6 +164,7 @@ impl<T: ?Sized> Drop for Xrc<T> { let state_ref = unsafe { &(*root.as_ptr()).state }; let state = state_ref.get(); + debug_assert!(state <= STATE_SHARED_MAX); if state != STATE_SHARED_INIT { state_ref.set(state - 1); return; @@ -184,6 +186,7 @@ impl<T> Clone for Xrc<T> { let state_ref = unsafe { &(*root.as_ptr()).state }; let state = state_ref.get(); + debug_assert!(state <= STATE_SHARED_MAX); if state == STATE_SHARED_MAX { panic!("ref count overflow"); } @@ -243,6 +246,7 @@ mod tests { use std::pin::pin; use std::ptr; use std::rc::Rc; + use std::panic::{self, AssertUnwindSafe}; fn iter_pinned_mut<T>(slice: Pin<&mut [T]>) -> impl Iterator<Item = Pin<&mut T>> { unsafe { @@ -260,6 +264,21 @@ mod tests { assert_eq!(xrc.0, 42); } + #[test] + fn unpin_hack() { + let mut root = pin!(Root::new()); + let xrc = root.as_mut().unclaimed().claim(NoReclaim(42)); + + let res = panic::catch_unwind(AssertUnwindSafe(|| { + // This must not create an unique borrow ... + let _ = root.unclaimed(); + })); + assert!(res.is_err()); + + // ... to not invalidate this shared read-only borrow. + assert_eq!(xrc.0, 42); + } + #[test] #[ignore = "will abort"] fn abort() {