{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreibbshbma6jts2lwuynaspgdtxlgw4c2ewmtfojthl2f2z5fmt6cbq",
    "uri": "at://did:plc:ivbknywyskln22er3nkssdhl/app.bsky.feed.post/3mlvplgszthy2"
  },
  "path": "/t/reducing-raw-pointer-footguns-preventing-reference-aliasing-violations-at-compile-time/24301#post_6",
  "publishedAt": "2026-05-15T14:29:35.000Z",
  "site": "https://internals.rust-lang.org",
  "textContent": "I've gone through the documentation and you're right. We can't create a const pointer while a `&mut` is active, nor can we read from pointers when that mutable reference exists. Writing through a mut pointer is also can't if any `&` or `&mut` are active, creating a `&mut` invalidates existing raw pointers\n\nI've updated the design to provide compile time error for that cases and separated the code\n\n\n    use std::marker::PhantomData;\n    use std::ptr::NonNull;\n\n    pub struct AliasingGuardMut<'a, T: ?Sized> {\n        ptr: NonNull<T>,\n\n        // SAFETY:\n        // This models exclusive mutable ownership over `T` for lifetime `'a`.\n        //\n        // The guard conceptually behaves like it owns an `&'a mut T`,\n        // which prevents aliasing mutable borrows through Rust's borrow checker.\n        //\n        // `PhantomData<&'a mut T>` is important because:\n        // - it enforces invariance over `T`\n        // - it tells the compiler this type semantically contains `&mut T`\n        // - it enables borrow checking rules for aliasing/exclusivity\n        // - it prevents multiple mutable guards existing simultaneously in safe code\n        _marker: PhantomData<&'a mut T>,\n    }\n\n    impl<'a, T: ?Sized> AliasingGuardMut<'a, T> {\n        #[inline(always)]\n        pub fn from_reference(value: &'a mut T) -> Self {\n            Self {\n                // SAFETY:\n                // `NonNull::from` is safe because `&mut T` is guaranteed:\n                // - non-null\n                // - properly aligned\n                // - valid for reads/writes for `'a`\n                ptr: NonNull::from(value),\n\n                _marker: PhantomData,\n            }\n        }\n\n        #[inline(always)]\n        pub fn immutable_reference(&self) -> &T {\n            // SAFETY:\n            // The original `&mut T` guarantees:\n            // - pointer validity\n            // - proper alignment\n            // - initialized memory\n            //\n            // Returning `&T` from `&self` is safe because:\n            // - immutable references may alias other immutable references\n            // - Rust reference rules prevent obtaining `&mut self` simultaneously with this reference in safe code\n            unsafe { self.ptr.as_ref() }\n        }\n\n        #[inline(always)]\n        pub fn mutable_reference(&mut self) -> &mut T {\n            // SAFETY:\n            // `&mut self` guarantees exclusive access to the guard.\n            //\n            // Because the guard semantically owns an exclusive `&mut T`,\n            // this ensures no competing mutable references can exist\n            // through this API in safe Rust.\n            //\n            // WARNING:\n            // Raw pointers previously extracted from this guard may still\n            // exist and can violate aliasing rules if used incorrectly.\n            // Safe Rust callers cannot trigger UB here, but unsafe callers can.\n            unsafe { self.ptr.as_mut() }\n        }\n\n        #[inline(always)]\n        pub fn with_immutable_reference<R>(&self, f: impl FnOnce(&T) -> R) -> R {\n            // SAFETY:\n            // Same reasoning as `immutable_reference`.\n            //\n            // The reference is scoped to the closure call,\n            // preventing it from escaping accidentally.\n            unsafe { f(self.ptr.as_ref()) }\n        }\n\n        #[inline(always)]\n        pub fn with_mutable_reference<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R {\n            // SAFETY:\n            // Same reasoning as `mutable_reference`.\n            //\n            // The mutable reference is scoped to the closure execution,\n            // which helps reduce accidental misuse duration.\n            unsafe { f(self.ptr.as_mut()) }\n        }\n\n        #[inline(always)]\n        pub fn with_immutable_pointer<R>(&self, f: impl FnOnce(*const T) -> R) -> R {\n            // SAFETY:\n            // - Rust reference rules prevent obtaining `&mut self` simultaneously with this reference in safe code\n            //\n            // In particular:\n            // - The immutable raw pointer is scoped to the closure execution\n            // which makes able to create `&mut` without invalidating the pointers\n            // - It prevents calling immutable raw pointer while `&mut` is still active because it violates the aliasing rules\n            f(self.ptr.as_ptr())\n        }\n\n        #[inline(always)]\n        pub fn with_mutable_pointer<R>(&mut self, f: impl FnOnce(*mut T) -> R) -> R {\n            // SAFETY:\n            // - Rust reference rules prevent obtaining `&mut self` simultaneously with this reference in safe code\n            //\n            // In particular:\n            // - The mutable raw pointer is scoped to the closure execution\n            // which makes able to create `&` or `&mut` without invalidating the pointers\n            // - It prevents calling mutable raw pointer while `&` or `&mut` is still active because it violates the aliasing rules\n            f(self.ptr.as_ptr())\n        }\n\n        #[inline(always)]\n        pub unsafe fn as_ptr(&mut self) -> *mut T {\n            // SAFETY:\n            // This exists to make if closure based pointer is not enough, then this unsafe method can be used\n            // Returning raw pointers is safe by itself.\n            //\n            // However, once the pointer escapes, this type can no longer\n            // enforce aliasing guarantees.\n            //\n            // The caller must ensure:\n            // - no invalid reference/raw-pointer combinations are used\n            // - no aliasing UB occurs\n            // - do not write to the pointer while `&` or `&mut` to same memory is still active\n            // - do not read the pointer while `&mut` to same memory is still active\n            // - be aware that `&mut` creation that points to same address of this pointer will invalidate this pointer\n            // - pointer is not used after underlying value becomes invalid\n            self.ptr.as_ptr()\n        }\n\n        #[inline(always)]\n        pub fn close(self) {\n            // SAFETY:\n            // Consuming `self` ends the guard lifetime early.\n            //\n            // This can be useful to release the conceptual mutable borrow\n            // before the surrounding scope ends.\n        }\n    }\n\n    fn main() {\n        let mut a = String::from(\"hello\");\n\n        let mut guard = AliasingGuardMut::from_reference(&mut a);\n\n        let b = guard.mutable_reference();\n        *b = String::from(\"reference from raw ptr\");\n\n        // these will give compile time error\n\n        //let c_illegal = guard.immutable_reference();\n        //let d_illegal = guard.mutable_reference();\n\n        *b = String::from(\"reference from raw ptr 2\");\n\n        let e = guard.immutable_reference();\n\n        // this will give compile time error\n\n        // let f_illegal = guard.mutable_reference();\n\n        println!(\"{}\", *e);\n\n        let g = guard.mutable_reference();\n\n        /* this will give compile time error\n        guard.with_immutable_pointer(|ptr| {\n            println!(\"{}\", unsafe { &*ptr });\n        });\n        */\n\n        /* this will give compile time error\n        guard.with_mutable_pointer(|ptr| unsafe {\n            *ptr = String::from(\"hello\");\n        });\n        */\n\n        /* this will give compile time error\n        guard.with_immutable_reference(|reff| {\n            println!(\"{}\", *reff);\n        });\n        */\n\n        /* this will give compile time error\n        guard.with_mutable_reference(|reff| {\n            *reff = String::from(\"hello\");\n        });\n        */\n\n        *g = String::from(\"reference from raw ptr 3\");\n\n        // drop(guard) or guard.close() to close the guard without waiting an end of scope\n\n        println!(\"{}\", a);\n\n\n    }\n",
  "title": "Reducing Raw Pointer Footguns: Preventing Reference Aliasing Violations at Compile Time"
}