{
"$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"
}