xref: /aosp_15_r20/external/crosvm/base/src/alloc.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::alloc::alloc;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::alloc::alloc_zeroed;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::alloc::dealloc;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::alloc::Layout;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::cmp::min;
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker /// A contiguous memory allocation with a specified size and alignment, with a
12*bb4ee6a4SAndroid Build Coastguard Worker /// Drop impl to perform the deallocation.
13*bb4ee6a4SAndroid Build Coastguard Worker ///
14*bb4ee6a4SAndroid Build Coastguard Worker /// Conceptually this is like a Box<[u8]> but for which we can select a minimum
15*bb4ee6a4SAndroid Build Coastguard Worker /// required alignment at the time of allocation.
16*bb4ee6a4SAndroid Build Coastguard Worker ///
17*bb4ee6a4SAndroid Build Coastguard Worker /// # Example
18*bb4ee6a4SAndroid Build Coastguard Worker ///
19*bb4ee6a4SAndroid Build Coastguard Worker /// ```
20*bb4ee6a4SAndroid Build Coastguard Worker /// use std::alloc::Layout;
21*bb4ee6a4SAndroid Build Coastguard Worker /// use std::mem;
22*bb4ee6a4SAndroid Build Coastguard Worker /// use base::LayoutAllocation;
23*bb4ee6a4SAndroid Build Coastguard Worker ///
24*bb4ee6a4SAndroid Build Coastguard Worker /// #[repr(C)]
25*bb4ee6a4SAndroid Build Coastguard Worker /// struct Header {
26*bb4ee6a4SAndroid Build Coastguard Worker ///     q: usize,
27*bb4ee6a4SAndroid Build Coastguard Worker ///     entries: [Entry; 0], // flexible array member
28*bb4ee6a4SAndroid Build Coastguard Worker /// }
29*bb4ee6a4SAndroid Build Coastguard Worker ///
30*bb4ee6a4SAndroid Build Coastguard Worker /// #[repr(C)]
31*bb4ee6a4SAndroid Build Coastguard Worker /// struct Entry {
32*bb4ee6a4SAndroid Build Coastguard Worker ///     e: usize,
33*bb4ee6a4SAndroid Build Coastguard Worker /// }
34*bb4ee6a4SAndroid Build Coastguard Worker ///
35*bb4ee6a4SAndroid Build Coastguard Worker /// fn demo(num_entries: usize) {
36*bb4ee6a4SAndroid Build Coastguard Worker ///     let size = mem::size_of::<Header>() + num_entries * mem::size_of::<Entry>();
37*bb4ee6a4SAndroid Build Coastguard Worker ///     let layout = Layout::from_size_align(size, mem::align_of::<Header>()).unwrap();
38*bb4ee6a4SAndroid Build Coastguard Worker ///     let mut allocation = LayoutAllocation::zeroed(layout);
39*bb4ee6a4SAndroid Build Coastguard Worker ///
40*bb4ee6a4SAndroid Build Coastguard Worker ///     // SAFETY:
41*bb4ee6a4SAndroid Build Coastguard Worker ///     // Safe to obtain an exclusive reference because there are no other
42*bb4ee6a4SAndroid Build Coastguard Worker ///     // references to the allocation yet and all-zero is a valid bit pattern for
43*bb4ee6a4SAndroid Build Coastguard Worker ///     // our header.
44*bb4ee6a4SAndroid Build Coastguard Worker ///     let header = unsafe { allocation.as_mut::<Header>() };
45*bb4ee6a4SAndroid Build Coastguard Worker /// }
46*bb4ee6a4SAndroid Build Coastguard Worker /// ```
47*bb4ee6a4SAndroid Build Coastguard Worker pub struct LayoutAllocation {
48*bb4ee6a4SAndroid Build Coastguard Worker     ptr: *mut u8,
49*bb4ee6a4SAndroid Build Coastguard Worker     layout: Layout,
50*bb4ee6a4SAndroid Build Coastguard Worker }
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker impl LayoutAllocation {
53*bb4ee6a4SAndroid Build Coastguard Worker     /// Allocates memory with the specified size and alignment. The content is
54*bb4ee6a4SAndroid Build Coastguard Worker     /// not initialized.
55*bb4ee6a4SAndroid Build Coastguard Worker     ///
56*bb4ee6a4SAndroid Build Coastguard Worker     /// Uninitialized data is not safe to read. Further, it is not safe to
57*bb4ee6a4SAndroid Build Coastguard Worker     /// obtain a reference to data potentially holding a bit pattern
58*bb4ee6a4SAndroid Build Coastguard Worker     /// incompatible with its type, for example an uninitialized bool or enum.
uninitialized(layout: Layout) -> Self59*bb4ee6a4SAndroid Build Coastguard Worker     pub fn uninitialized(layout: Layout) -> Self {
60*bb4ee6a4SAndroid Build Coastguard Worker         let ptr = if layout.size() > 0 {
61*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
62*bb4ee6a4SAndroid Build Coastguard Worker             // Safe as long as we guarantee layout.size() > 0.
63*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { alloc(layout) }
64*bb4ee6a4SAndroid Build Coastguard Worker         } else {
65*bb4ee6a4SAndroid Build Coastguard Worker             layout.align() as *mut u8
66*bb4ee6a4SAndroid Build Coastguard Worker         };
67*bb4ee6a4SAndroid Build Coastguard Worker         LayoutAllocation { ptr, layout }
68*bb4ee6a4SAndroid Build Coastguard Worker     }
69*bb4ee6a4SAndroid Build Coastguard Worker 
70*bb4ee6a4SAndroid Build Coastguard Worker     /// Allocates memory with the specified size and alignment and initializes
71*bb4ee6a4SAndroid Build Coastguard Worker     /// the content to all zero-bytes.
72*bb4ee6a4SAndroid Build Coastguard Worker     ///
73*bb4ee6a4SAndroid Build Coastguard Worker     /// Note that zeroing the memory does not necessarily make it safe to obtain
74*bb4ee6a4SAndroid Build Coastguard Worker     /// a reference to the allocation. Depending on the intended type T,
75*bb4ee6a4SAndroid Build Coastguard Worker     /// all-zero may or may not be a legal bit pattern for that type. For
76*bb4ee6a4SAndroid Build Coastguard Worker     /// example obtaining a reference would immediately be undefined behavior if
77*bb4ee6a4SAndroid Build Coastguard Worker     /// one of the fields has type NonZeroUsize.
zeroed(layout: Layout) -> Self78*bb4ee6a4SAndroid Build Coastguard Worker     pub fn zeroed(layout: Layout) -> Self {
79*bb4ee6a4SAndroid Build Coastguard Worker         let ptr = if layout.size() > 0 {
80*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
81*bb4ee6a4SAndroid Build Coastguard Worker             // Safe as long as we guarantee layout.size() > 0.
82*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { alloc_zeroed(layout) }
83*bb4ee6a4SAndroid Build Coastguard Worker         } else {
84*bb4ee6a4SAndroid Build Coastguard Worker             layout.align() as *mut u8
85*bb4ee6a4SAndroid Build Coastguard Worker         };
86*bb4ee6a4SAndroid Build Coastguard Worker         LayoutAllocation { ptr, layout }
87*bb4ee6a4SAndroid Build Coastguard Worker     }
88*bb4ee6a4SAndroid Build Coastguard Worker 
89*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns a raw pointer to the allocated data.
as_ptr<T>(&self) -> *mut T90*bb4ee6a4SAndroid Build Coastguard Worker     pub fn as_ptr<T>(&self) -> *mut T {
91*bb4ee6a4SAndroid Build Coastguard Worker         self.ptr as *mut T
92*bb4ee6a4SAndroid Build Coastguard Worker     }
93*bb4ee6a4SAndroid Build Coastguard Worker 
94*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns a reference to the `Layout` used to create this allocation.
layout(&self) -> &Layout95*bb4ee6a4SAndroid Build Coastguard Worker     pub fn layout(&self) -> &Layout {
96*bb4ee6a4SAndroid Build Coastguard Worker         &self.layout
97*bb4ee6a4SAndroid Build Coastguard Worker     }
98*bb4ee6a4SAndroid Build Coastguard Worker 
99*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns a shared reference to the allocated data.
100*bb4ee6a4SAndroid Build Coastguard Worker     ///
101*bb4ee6a4SAndroid Build Coastguard Worker     /// # Safety
102*bb4ee6a4SAndroid Build Coastguard Worker     ///
103*bb4ee6a4SAndroid Build Coastguard Worker     /// Caller is responsible for ensuring that the data behind this pointer has
104*bb4ee6a4SAndroid Build Coastguard Worker     /// been initialized as much as necessary and that there are no already
105*bb4ee6a4SAndroid Build Coastguard Worker     /// existing mutable references to any part of the data.
as_ref<T>(&self) -> &T106*bb4ee6a4SAndroid Build Coastguard Worker     pub unsafe fn as_ref<T>(&self) -> &T {
107*bb4ee6a4SAndroid Build Coastguard Worker         &*self.as_ptr()
108*bb4ee6a4SAndroid Build Coastguard Worker     }
109*bb4ee6a4SAndroid Build Coastguard Worker 
110*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns an exclusive reference to the allocated data.
111*bb4ee6a4SAndroid Build Coastguard Worker     ///
112*bb4ee6a4SAndroid Build Coastguard Worker     /// # Safety
113*bb4ee6a4SAndroid Build Coastguard Worker     ///
114*bb4ee6a4SAndroid Build Coastguard Worker     /// Caller is responsible for ensuring that the data behind this pointer has
115*bb4ee6a4SAndroid Build Coastguard Worker     /// been initialized as much as necessary and that there are no already
116*bb4ee6a4SAndroid Build Coastguard Worker     /// existing references to any part of the data.
as_mut<T>(&mut self) -> &mut T117*bb4ee6a4SAndroid Build Coastguard Worker     pub unsafe fn as_mut<T>(&mut self) -> &mut T {
118*bb4ee6a4SAndroid Build Coastguard Worker         &mut *self.as_ptr()
119*bb4ee6a4SAndroid Build Coastguard Worker     }
120*bb4ee6a4SAndroid Build Coastguard Worker 
121*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns a shared slice reference to the allocated data.
122*bb4ee6a4SAndroid Build Coastguard Worker     ///
123*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
124*bb4ee6a4SAndroid Build Coastguard Worker     ///
125*bb4ee6a4SAndroid Build Coastguard Worker     /// `num_elements` - Number of `T` elements to include in the slice.
126*bb4ee6a4SAndroid Build Coastguard Worker     ///                  The length of the slice will be capped to the allocation's size.
127*bb4ee6a4SAndroid Build Coastguard Worker     ///                  Caller must ensure that any sliced elements are initialized.
128*bb4ee6a4SAndroid Build Coastguard Worker     ///
129*bb4ee6a4SAndroid Build Coastguard Worker     /// # Safety
130*bb4ee6a4SAndroid Build Coastguard Worker     ///
131*bb4ee6a4SAndroid Build Coastguard Worker     /// Caller is responsible for ensuring that the data behind this pointer has
132*bb4ee6a4SAndroid Build Coastguard Worker     /// been initialized as much as necessary and that there are no already
133*bb4ee6a4SAndroid Build Coastguard Worker     /// existing mutable references to any part of the data.
as_slice<T>(&self, num_elements: usize) -> &[T]134*bb4ee6a4SAndroid Build Coastguard Worker     pub unsafe fn as_slice<T>(&self, num_elements: usize) -> &[T] {
135*bb4ee6a4SAndroid Build Coastguard Worker         let len = min(num_elements, self.layout.size() / std::mem::size_of::<T>());
136*bb4ee6a4SAndroid Build Coastguard Worker         std::slice::from_raw_parts(self.as_ptr(), len)
137*bb4ee6a4SAndroid Build Coastguard Worker     }
138*bb4ee6a4SAndroid Build Coastguard Worker 
139*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns an exclusive slice reference to the allocated data.
140*bb4ee6a4SAndroid Build Coastguard Worker     ///
141*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
142*bb4ee6a4SAndroid Build Coastguard Worker     ///
143*bb4ee6a4SAndroid Build Coastguard Worker     /// `num_elements` - Number of `T` elements to include in the slice.
144*bb4ee6a4SAndroid Build Coastguard Worker     ///                  The length of the slice will be capped to the allocation's size.
145*bb4ee6a4SAndroid Build Coastguard Worker     ///                  Caller must ensure that any sliced elements are initialized.
146*bb4ee6a4SAndroid Build Coastguard Worker     ///
147*bb4ee6a4SAndroid Build Coastguard Worker     /// # Safety
148*bb4ee6a4SAndroid Build Coastguard Worker     ///
149*bb4ee6a4SAndroid Build Coastguard Worker     /// Caller is responsible for ensuring that the data behind this pointer has
150*bb4ee6a4SAndroid Build Coastguard Worker     /// been initialized as much as necessary and that there are no already
151*bb4ee6a4SAndroid Build Coastguard Worker     /// existing references to any part of the data.
as_mut_slice<T>(&mut self, num_elements: usize) -> &mut [T]152*bb4ee6a4SAndroid Build Coastguard Worker     pub unsafe fn as_mut_slice<T>(&mut self, num_elements: usize) -> &mut [T] {
153*bb4ee6a4SAndroid Build Coastguard Worker         let len = min(num_elements, self.layout.size() / std::mem::size_of::<T>());
154*bb4ee6a4SAndroid Build Coastguard Worker         std::slice::from_raw_parts_mut(self.as_ptr(), len)
155*bb4ee6a4SAndroid Build Coastguard Worker     }
156*bb4ee6a4SAndroid Build Coastguard Worker }
157*bb4ee6a4SAndroid Build Coastguard Worker 
158*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for LayoutAllocation {
drop(&mut self)159*bb4ee6a4SAndroid Build Coastguard Worker     fn drop(&mut self) {
160*bb4ee6a4SAndroid Build Coastguard Worker         if self.layout.size() > 0 {
161*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
162*bb4ee6a4SAndroid Build Coastguard Worker             // Safe as long as we guarantee layout.size() > 0.
163*bb4ee6a4SAndroid Build Coastguard Worker             unsafe {
164*bb4ee6a4SAndroid Build Coastguard Worker                 dealloc(self.ptr, self.layout);
165*bb4ee6a4SAndroid Build Coastguard Worker             }
166*bb4ee6a4SAndroid Build Coastguard Worker         }
167*bb4ee6a4SAndroid Build Coastguard Worker     }
168*bb4ee6a4SAndroid Build Coastguard Worker }
169*bb4ee6a4SAndroid Build Coastguard Worker 
170*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
171*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
172*bb4ee6a4SAndroid Build Coastguard Worker     use std::mem::align_of;
173*bb4ee6a4SAndroid Build Coastguard Worker     use std::mem::size_of;
174*bb4ee6a4SAndroid Build Coastguard Worker 
175*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
176*bb4ee6a4SAndroid Build Coastguard Worker 
177*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_as_slice_u32()178*bb4ee6a4SAndroid Build Coastguard Worker     fn test_as_slice_u32() {
179*bb4ee6a4SAndroid Build Coastguard Worker         let layout = Layout::from_size_align(size_of::<u32>() * 15, align_of::<u32>()).unwrap();
180*bb4ee6a4SAndroid Build Coastguard Worker         let allocation = LayoutAllocation::zeroed(layout);
181*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
182*bb4ee6a4SAndroid Build Coastguard Worker         // Slice less than the allocation size, which will return a slice of only the requested
183*bb4ee6a4SAndroid Build Coastguard Worker         // length.
184*bb4ee6a4SAndroid Build Coastguard Worker         let slice: &[u32] = unsafe { allocation.as_slice(15) };
185*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(slice.len(), 15);
186*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(slice[0], 0);
187*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(slice[14], 0);
188*bb4ee6a4SAndroid Build Coastguard Worker     }
189*bb4ee6a4SAndroid Build Coastguard Worker 
190*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_as_slice_u32_smaller_len()191*bb4ee6a4SAndroid Build Coastguard Worker     fn test_as_slice_u32_smaller_len() {
192*bb4ee6a4SAndroid Build Coastguard Worker         let layout = Layout::from_size_align(size_of::<u32>() * 15, align_of::<u32>()).unwrap();
193*bb4ee6a4SAndroid Build Coastguard Worker         let allocation = LayoutAllocation::zeroed(layout);
194*bb4ee6a4SAndroid Build Coastguard Worker 
195*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
196*bb4ee6a4SAndroid Build Coastguard Worker         // Slice less than the allocation size, which will return a slice of only the requested
197*bb4ee6a4SAndroid Build Coastguard Worker         // length.
198*bb4ee6a4SAndroid Build Coastguard Worker         let slice: &[u32] = unsafe { allocation.as_slice(5) };
199*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(slice.len(), 5);
200*bb4ee6a4SAndroid Build Coastguard Worker     }
201*bb4ee6a4SAndroid Build Coastguard Worker 
202*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_as_slice_u32_larger_len()203*bb4ee6a4SAndroid Build Coastguard Worker     fn test_as_slice_u32_larger_len() {
204*bb4ee6a4SAndroid Build Coastguard Worker         let layout = Layout::from_size_align(size_of::<u32>() * 15, align_of::<u32>()).unwrap();
205*bb4ee6a4SAndroid Build Coastguard Worker         let allocation = LayoutAllocation::zeroed(layout);
206*bb4ee6a4SAndroid Build Coastguard Worker 
207*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
208*bb4ee6a4SAndroid Build Coastguard Worker         // Slice more than the allocation size, which will clamp the returned slice len to the
209*bb4ee6a4SAndroid Build Coastguard Worker         // limit.
210*bb4ee6a4SAndroid Build Coastguard Worker         let slice: &[u32] = unsafe { allocation.as_slice(100) };
211*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(slice.len(), 15);
212*bb4ee6a4SAndroid Build Coastguard Worker     }
213*bb4ee6a4SAndroid Build Coastguard Worker 
214*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_as_slice_u32_remainder()215*bb4ee6a4SAndroid Build Coastguard Worker     fn test_as_slice_u32_remainder() {
216*bb4ee6a4SAndroid Build Coastguard Worker         // Allocate a buffer that is not a multiple of u32 in size.
217*bb4ee6a4SAndroid Build Coastguard Worker         let layout = Layout::from_size_align(size_of::<u32>() * 15 + 2, align_of::<u32>()).unwrap();
218*bb4ee6a4SAndroid Build Coastguard Worker         let allocation = LayoutAllocation::zeroed(layout);
219*bb4ee6a4SAndroid Build Coastguard Worker 
220*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
221*bb4ee6a4SAndroid Build Coastguard Worker         // Slice as many u32s as possible, which should return a slice that only includes the full
222*bb4ee6a4SAndroid Build Coastguard Worker         // u32s, not the trailing 2 bytes.
223*bb4ee6a4SAndroid Build Coastguard Worker         let slice: &[u32] = unsafe { allocation.as_slice(100) };
224*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(slice.len(), 15);
225*bb4ee6a4SAndroid Build Coastguard Worker     }
226*bb4ee6a4SAndroid Build Coastguard Worker }
227