From 0faba12c6809116abeae6662aa02738cf709f003 Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Thu, 1 Feb 2024 00:40:07 +0100
Subject: [PATCH] bonus asserts + test

---
 src/lib.rs | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/src/lib.rs b/src/lib.rs
index 46b9828..f76cb79 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() {
-- 
GitLab