In rust, &mut T is not normally allowed to refer to aliasing memory. But when writing self
referential structs, one needs aliasing mutable references. This crate provides the
UnsafeAliasCell<T> primitive type. It works similar to the UnsafeCell<T> from the
stdlib:
UnsafeCell<T>opts-out of the immutability guarantee for&T: a shared reference&UnsafeCell<T>may point to data that is being mutated.
UnsafeAliasCell<T> opts-out of the uniqueness guarantee for &mut T: a unique mutable reference
&mut UnsafeAliasCell<T> may point to data that is being mutated.
Using UnsafeAliasCell<T>
One needs to be careful, when using UnsafeAliasCell<T>, because wrong usage leads to undefined
behavior.
Even when using UnsafeAliasCell<T> it is considered undefined behavior to create multiple
aliasing &mut T. But you are allowed to create multiple aliasing *mut T/*const T.
Use UnsafeAliasCell<T> on the part that you intend to alias:
# use unsafe_alias_cell::UnsafeAliasCell;
pub struct SelfReferential {
item: UnsafeAliasCell<i32>,
ptr: *const i32,
}Now you are allowed to call .get() on item and store that pointer in ptr. For as long as
that SelfReferential stays pinned, you can use
ptr to read the item.
Implementing Unpin for any type containing a UnsafeAliasCell<T> is UB.
It is UB to cast the pointer returned by .get() to
&mut T, when there exists another pointer (&T,*const Tor*mut T) pointing to the inner of the cell.&T, when there exists another mutable pointer (*mut T) pointing to the inner of the cell.
Similar to UnsafeCell<T> you need to ensure the aliasing rules for any reference you create
(taken from the stdlib):
- If you create a safe reference with lifetime
'a(either a&Tor&mut Treference) that is accessible by safe code (for example, because you returned it), then you must not access the data in any way that contradicts that reference for the remainder of'a. For example, this means that if you take the*mut Tfrom anUnsafeAliasCell<T>and cast it to an&T, then the data in T must remain immutable (modulo anyUnsafeCell<U>/UnsafeAliasCell<U>data found within T, of course) until that reference’s lifetime expires. Similarly, if you create a&mut Treference that is released to safe code, then you must not access the data within theUnsafeAliasCell<T>until that reference expires. - At all times, you must avoid data races. If multiple threads have access to the same
UnsafeAliasCell<T>, then any writes must have a proper happens-before relation to all other accesses (or use atomics).
Under the current rules, all types that are !Unpin are allowed to be aliased. So for
UnsafeAliasCell<T> to be sound, it is therefore required to be contained in only !Unpin types.
UnsafeAliasCell<T> is made up of UnsafeCell<T> and PhantomPinned to enable both interior
mutability and allow aliasing.