xref: /aosp_15_r20/external/crosvm/common/data_model/src/flexible_array.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2019 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! A wrapper for structures that contain flexible arrays.
6 
7 use std::marker::PhantomData;
8 use std::mem::size_of;
9 
10 // Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`.
vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T>11 fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
12     let rounded_size = (size_in_bytes + size_of::<T>() - 1) / size_of::<T>();
13     let mut v = Vec::with_capacity(rounded_size);
14     v.resize_with(rounded_size, T::default);
15     v
16 }
17 
18 /// The kernel API has many structs that resemble the following `Foo` structure:
19 ///
20 /// ```ignore
21 /// #[repr(C)]
22 /// struct Foo {
23 ///    some_data: u32,
24 ///    entries: __IncompleteArrayField<__u32>,
25 /// }
26 /// ```
27 ///
28 /// In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would
29 /// not include any space for `entries`. To make the allocation large enough while still being
30 /// aligned for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually
31 /// be used as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be
32 /// contiguous with `Foo`. This function is used to make the `Vec<Foo>` with enough space for
33 /// `count` entries.
vec_with_array_field<T: Default, F>(count: usize) -> Vec<T>34 pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
35     let element_space = count * size_of::<F>();
36     let vec_size_bytes = size_of::<T>() + element_space;
37     vec_with_size_in_bytes(vec_size_bytes)
38 }
39 
40 /// The following code provides generic helpers for creating and accessing flexible array structs.
41 /// A complete definition of flexible array structs is found in the ISO 9899 specification
42 /// <http://www.iso-9899.info/n1570.html>. A flexible array struct is of the form:
43 ///
44 /// ```ignore
45 /// #[repr(C)]
46 /// struct T {
47 ///    some_data: u32,
48 ///    nents: u32,
49 ///    entries: __IncompleteArrayField<S>,
50 /// }
51 /// ```
52 /// where:
53 ///
54 /// - `T` is the flexible array struct type
55 /// - `S` is the flexible array type
56 /// - `nents` is the flexible array length
57 /// - `entries` is the flexible array member
58 ///
59 /// These structures are used by the kernel API.
60 
61 /// A collection of methods that are required by the FlexibleArrayWrapper type.
62 ///
63 /// When implemented for `T`, this trait allows the caller to set number of `S` entries and
64 /// retrieve a slice of `S` entries.  Trait methods must only be called by the FlexibleArrayWrapper
65 /// type.  Don't implement this trait directly, use the flexible_array! macro to avoid duplication.
66 pub trait FlexibleArray<S> {
67     /// Implementations must set flexible array length in the flexible array struct to the value
68     /// specified by `len`. Appropriate conversions (i.e, usize to u32) are allowed so long as
69     /// they don't overflow or underflow.
set_len(&mut self, len: usize)70     fn set_len(&mut self, len: usize);
71     /// Implementations must return the length of the flexible array member.  Appropriate
72     /// conversions (i.e, usize to u32) are allowed so long as they don't overflow or underflow.
get_len(&self) -> usize73     fn get_len(&self) -> usize;
74     /// Implementations must return a slice of flexible array member of length `len`.
75     /// # Safety
76     /// Do not use this function directly, as the FlexibleArrayWrapper will guarantee safety.
get_slice(&self, len: usize) -> &[S]77     unsafe fn get_slice(&self, len: usize) -> &[S];
78     /// Implementations must return a mutable slice of flexible array member of length `len`.
79     /// # Safety
80     /// Do not use this function directly, as the FlexibleArrayWrapper will guarantee safety.
get_mut_slice(&mut self, len: usize) -> &mut [S]81     unsafe fn get_mut_slice(&mut self, len: usize) -> &mut [S];
82 }
83 
84 /// Always use this macro for implementing the FlexibleArray<`S`> trait for a given `T`.  There
85 /// exists an 1:1 mapping of macro identifiers to the definitions in the FlexibleArray<`S`>
86 /// documentation, so refer to that for more information.
87 #[macro_export]
88 macro_rules! flexible_array_impl {
89     ($T:ident, $S:ident, $nents:ident, $entries:ident) => {
90         impl $crate::FlexibleArray<$S> for $T {
91             fn set_len(&mut self, len: usize) {
92                 self.$nents = ::std::convert::TryInto::try_into(len).unwrap();
93             }
94 
95             fn get_len(&self) -> usize {
96                 self.$nents as usize
97             }
98 
99             unsafe fn get_slice(&self, len: usize) -> &[$S] {
100                 self.$entries.as_slice(len)
101             }
102 
103             unsafe fn get_mut_slice(&mut self, len: usize) -> &mut [$S] {
104                 self.$entries.as_mut_slice(len)
105             }
106         }
107     };
108 }
109 
110 pub struct FlexibleArrayWrapper<T, S> {
111     entries: Vec<T>,
112     phantom: PhantomData<S>,
113     allocated_len: usize,
114 }
115 
116 /// Convenience wrapper for flexible array structs.
117 ///
118 /// The FlexibleArray trait must be implemented for the flexible array struct before using this
119 /// wrapper.
120 impl<T, S> FlexibleArrayWrapper<T, S>
121 where
122     T: FlexibleArray<S> + Default,
123 {
124     /// Creates a new FlexibleArrayWrapper for the given flexible array struct type and flexible
125     /// array type. The flexible array length is set to `array_len`. vec_with_array_field is used
126     /// to make sure the resultant wrapper is appropriately sized.
new(array_len: usize) -> FlexibleArrayWrapper<T, S>127     pub fn new(array_len: usize) -> FlexibleArrayWrapper<T, S> {
128         let mut entries = vec_with_array_field::<T, S>(array_len);
129         entries[0].set_len(array_len);
130 
131         FlexibleArrayWrapper {
132             entries,
133             phantom: PhantomData,
134             allocated_len: array_len,
135         }
136     }
137 
138     /// Mapping the unsized array to a slice is unsafe because the length isn't known.  Using
139     /// the length we originally allocated with eliminates the possibility of overflow.
get_valid_len(&self) -> usize140     fn get_valid_len(&self) -> usize {
141         if self.entries[0].get_len() > self.allocated_len {
142             self.allocated_len
143         } else {
144             self.entries[0].get_len()
145         }
146     }
147 
148     /// Returns a slice of the flexible array member, for inspecting. To modify, use
149     /// mut_entries_slice instead.
entries_slice(&self) -> &[S]150     pub fn entries_slice(&self) -> &[S] {
151         let valid_length = self.get_valid_len();
152         // SAFETY:
153         // Safe because the length has been validated.
154         unsafe { self.entries[0].get_slice(valid_length) }
155     }
156 
157     /// Returns a mutable slice of the flexible array member, for modifying.
mut_entries_slice(&mut self) -> &mut [S]158     pub fn mut_entries_slice(&mut self) -> &mut [S] {
159         let valid_length = self.get_valid_len();
160         self.entries[0].set_len(valid_length);
161         // SAFETY:
162         // Safe because the length has been validated.
163         unsafe { self.entries[0].get_mut_slice(valid_length) }
164     }
165 
166     /// Get a pointer so it can be passed to the kernel. Callers must not access the flexible
167     /// array member.  Using this pointer is unsafe.
as_ptr(&self) -> *const T168     pub fn as_ptr(&self) -> *const T {
169         &self.entries[0]
170     }
171 
172     /// Get a mutable pointer so it can be passed to the kernel. Callers must not access the
173     /// flexible array member.  Using this pointer is unsafe.
as_mut_ptr(&mut self) -> *mut T174     pub fn as_mut_ptr(&mut self) -> *mut T {
175         &mut self.entries[0]
176     }
177 }
178