solana_stable_layout/
stable_vec.rs

1//! `Vec`, with a stable memory layout
2
3use std::{
4    marker::PhantomData,
5    mem::ManuallyDrop,
6    ops::{Deref, DerefMut},
7};
8
9/// `Vec`, with a stable memory layout
10///
11/// This container is used within the runtime to ensure memory mapping and memory accesses are
12/// valid.  We rely on known addresses and offsets within the runtime, and since `Vec`'s layout
13/// is allowed to change, we must provide a way to lock down the memory layout.  `StableVec`
14/// reimplements the bare minimum of `Vec`'s API sufficient only for the runtime's needs.
15///
16/// To ensure memory allocation and deallocation is handled correctly, it is only possible to
17/// create a new `StableVec` from an existing `Vec`.  This way we ensure all Rust invariants are
18/// upheld.
19///
20/// # Examples
21///
22/// Creating a `StableVec` from a `Vec`
23///
24/// ```
25/// # use solana_stable_layout::stable_vec::StableVec;
26/// let vec = vec!["meow", "woof", "moo"];
27/// let vec = StableVec::from(vec);
28/// ```
29#[repr(C)]
30pub struct StableVec<T> {
31    pub addr: u64,
32    pub cap: u64,
33    pub len: u64,
34    _marker: PhantomData<T>,
35}
36
37// We shadow these slice methods of the same name to avoid going through
38// `deref`, which creates an intermediate reference.
39impl<T> StableVec<T> {
40    #[inline]
41    pub fn as_vaddr(&self) -> u64 {
42        self.addr
43    }
44
45    #[inline]
46    pub fn len(&self) -> u64 {
47        self.len
48    }
49
50    #[inline]
51    pub fn is_empty(&self) -> bool {
52        self.len == 0
53    }
54}
55
56impl<T> AsRef<[T]> for StableVec<T> {
57    fn as_ref(&self) -> &[T] {
58        self.deref()
59    }
60}
61
62impl<T> AsMut<[T]> for StableVec<T> {
63    fn as_mut(&mut self) -> &mut [T] {
64        self.deref_mut()
65    }
66}
67
68impl<T> std::ops::Deref for StableVec<T> {
69    type Target = [T];
70
71    #[inline]
72    fn deref(&self) -> &[T] {
73        unsafe { core::slice::from_raw_parts(self.addr as usize as *mut T, self.len as usize) }
74    }
75}
76
77impl<T> std::ops::DerefMut for StableVec<T> {
78    #[inline]
79    fn deref_mut(&mut self) -> &mut [T] {
80        unsafe { core::slice::from_raw_parts_mut(self.addr as usize as *mut T, self.len as usize) }
81    }
82}
83
84impl<T: std::fmt::Debug> std::fmt::Debug for StableVec<T> {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        std::fmt::Debug::fmt(&**self, f)
87    }
88}
89
90macro_rules! impl_partial_eq {
91    ([$($vars:tt)*] $lhs:ty, $rhs:ty) => {
92        impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
93        where
94            T: PartialEq<U>,
95        {
96            #[inline]
97            fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
98        }
99    }
100}
101impl_partial_eq! { [] StableVec<T>, StableVec<U> }
102impl_partial_eq! { [] StableVec<T>, Vec<U> }
103impl_partial_eq! { [] Vec<T>, StableVec<U> }
104impl_partial_eq! { [] StableVec<T>, &[U] }
105impl_partial_eq! { [] StableVec<T>, &mut [U] }
106impl_partial_eq! { [] &[T], StableVec<U> }
107impl_partial_eq! { [] &mut [T], StableVec<U> }
108impl_partial_eq! { [] StableVec<T>, [U] }
109impl_partial_eq! { [] [T], StableVec<U> }
110impl_partial_eq! { [const N: usize] StableVec<T>, [U; N] }
111impl_partial_eq! { [const N: usize] StableVec<T>, &[U; N] }
112
113impl<T> From<Vec<T>> for StableVec<T> {
114    fn from(other: Vec<T>) -> Self {
115        // NOTE: This impl is basically copied from `Vec::into_raw_parts()`.  Once that fn is
116        // stabilized, use it here.
117        //
118        // We are going to pilfer `other`'s guts, and we don't want it to be dropped when it goes
119        // out of scope.
120        let mut other = ManuallyDrop::new(other);
121        Self {
122            // SAFETY: We have a valid Vec, so its ptr is non-null.
123            addr: other.as_mut_ptr() as u64, // Problematic if other is in 32-bit physical address space
124            cap: other.capacity() as u64,
125            len: other.len() as u64,
126            _marker: PhantomData,
127        }
128    }
129}
130
131impl<T> From<StableVec<T>> for Vec<T> {
132    fn from(other: StableVec<T>) -> Self {
133        // We are going to pilfer `other`'s guts, and we don't want it to be dropped when it goes
134        // out of scope.
135        let other = ManuallyDrop::new(other);
136        // SAFETY: We have a valid StableVec, which we can only get from a Vec.  Therefore it is
137        // safe to convert back to Vec. Assuming we're not starting with a vector in 64-bit virtual
138        // address space while building the app in 32-bit, and this vector is in that 32-bit physical
139        // space.
140        unsafe {
141            Vec::from_raw_parts(
142                other.addr as usize as *mut T,
143                other.len as usize,
144                other.cap as usize,
145            )
146        }
147    }
148}
149
150impl<T> Drop for StableVec<T> {
151    fn drop(&mut self) {
152        // We only allow creating a StableVec through creating a Vec.  To ensure we are dropped
153        // correctly, convert ourselves back to a Vec and let Vec's drop handling take over.
154        //
155        // SAFETY: We have a valid StableVec, which we can only get from a Vec.  Therefore it is
156        // safe to convert back to Vec.
157        let _vec = unsafe {
158            Vec::from_raw_parts(
159                self.addr as usize as *mut T,
160                self.len as usize,
161                self.cap as usize,
162            )
163        };
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use {
170        super::*,
171        memoffset::offset_of,
172        std::mem::{align_of, size_of},
173    };
174
175    #[test]
176    fn test_memory_layout() {
177        assert_eq!(offset_of!(StableVec<i32>, addr), 0);
178        assert_eq!(offset_of!(StableVec<i32>, cap), 8);
179        assert_eq!(offset_of!(StableVec<i32>, len), 16);
180        assert_eq!(align_of::<StableVec<i32>>(), 8);
181        assert_eq!(size_of::<StableVec<i32>>(), 8 + 8 + 8);
182
183        // create a vec with different values for cap and len
184        let vec = {
185            let mut vec = Vec::with_capacity(3);
186            vec.push(11);
187            vec.push(22);
188            vec
189        };
190        let vec = StableVec::from(vec);
191
192        let addr_vec = &vec as *const _ as usize;
193        let addr_ptr = addr_vec;
194        let addr_cap = addr_vec + 8;
195        let addr_len = addr_vec + 16;
196        assert_eq!(unsafe { *(addr_cap as *const usize) }, 3);
197        assert_eq!(unsafe { *(addr_len as *const usize) }, 2);
198
199        let ptr_data = addr_ptr as *const &[i32; 2];
200        assert_eq!(unsafe { *ptr_data }, &[11, 22]);
201    }
202}