Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/common/data_model/src/flexible_array.rs
5394 views
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
//! The following code provides generic helpers for creating and accessing flexible array structs.
8
//! A complete definition of flexible array structs is found in the ISO 9899 specification
9
//! <http://www.iso-9899.info/n1570.html>. A flexible array struct is of the form:
10
//!
11
//! ```ignore
12
//! #[repr(C)]
13
//! struct T {
14
//! some_data: u32,
15
//! nents: u32,
16
//! entries: __IncompleteArrayField<S>,
17
//! }
18
//! ```
19
//! where:
20
//!
21
//! - `T` is the flexible array struct type
22
//! - `S` is the flexible array type
23
//! - `nents` is the flexible array length
24
//! - `entries` is the flexible array member
25
//!
26
//! These structures are used by the kernel API.
27
28
use std::marker::PhantomData;
29
use std::mem::size_of;
30
31
// Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`.
32
fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
33
let rounded_size = size_in_bytes.div_ceil(size_of::<T>());
34
let mut v = Vec::with_capacity(rounded_size);
35
v.resize_with(rounded_size, T::default);
36
v
37
}
38
39
/// The kernel API has many structs that resemble the following `Foo` structure:
40
///
41
/// ```ignore
42
/// #[repr(C)]
43
/// struct Foo {
44
/// some_data: u32,
45
/// entries: __IncompleteArrayField<__u32>,
46
/// }
47
/// ```
48
///
49
/// In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would
50
/// not include any space for `entries`. To make the allocation large enough while still being
51
/// aligned for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually
52
/// be used as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be
53
/// contiguous with `Foo`. This function is used to make the `Vec<Foo>` with enough space for
54
/// `count` entries.
55
pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
56
let element_space = count * size_of::<F>();
57
let vec_size_bytes = size_of::<T>() + element_space;
58
vec_with_size_in_bytes(vec_size_bytes)
59
}
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.
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.
73
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.
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.
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.
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.
140
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.
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.
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.
168
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.
174
pub fn as_mut_ptr(&mut self) -> *mut T {
175
&mut self.entries[0]
176
}
177
}
178
179