• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
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     for _ in 0..rounded_size {
15         v.push(T::default())
16     }
17     v
18 }
19 
20 /// The kernel API has many structs that resemble the following `Foo` structure:
21 ///
22 /// ```ignore
23 /// #[repr(C)]
24 /// struct Foo {
25 ///    some_data: u32,
26 ///    entries: __IncompleteArrayField<__u32>,
27 /// }
28 /// ```
29 ///
30 /// In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would
31 /// not include any space for `entries`. To make the allocation large enough while still being
32 /// aligned for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually
33 /// be used as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be
34 /// contiguous with `Foo`. This function is used to make the `Vec<Foo>` with enough space for
35 /// `count` entries.
vec_with_array_field<T: Default, F>(count: usize) -> Vec<T>36 pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
37     let element_space = count * size_of::<F>();
38     let vec_size_bytes = size_of::<T>() + element_space;
39     vec_with_size_in_bytes(vec_size_bytes)
40 }
41 
42 /// The following code provides generic helpers for creating and accessing flexible array structs.
43 /// A complete definition of flexible array structs is found in the ISO 9899 specification
44 /// (http://www.iso-9899.info/n1570.html). A flexible array struct is of the form:
45 ///
46 /// ```ignore
47 /// #[repr(C)]
48 /// struct T {
49 ///    some_data: u32,
50 ///    nent: u32,
51 ///    entries: __IncompleteArrayField<S>,
52 /// }
53 /// ```
54 /// where:
55 ///
56 /// - `T` is the flexible array struct type
57 /// - `S` is the flexible array type
58 /// - `nent` is the flexible array length
59 /// - `entries` is the flexible array member
60 ///
61 /// These structures are used by the kernel API.
62 
63 /// A collection of methods that are required by the FlexibleArrayWrapper type.
64 ///
65 /// When implemented for `T`, this trait allows the caller to set number of `S` entries and
66 /// retrieve a slice of `S` entries.  Trait methods must only be called by the FlexibleArrayWrapper
67 /// type.
68 pub trait FlexibleArray<S> {
69     /// Implementations must set flexible array length in the flexible array struct to the value
70     /// specified by `len`. Appropriate conversions (i.e, usize to u32) are allowed so long as
71     /// they don't overflow or underflow.
set_len(&mut self, len: usize)72     fn set_len(&mut self, len: usize);
73     /// Implementations must return the length of the flexible array member.  Appropriate
74     /// conversions (i.e, usize to u32) are allowed so long as they don't overflow or underflow.
get_len(&self) -> usize75     fn get_len(&self) -> usize;
76     /// Implementations must return a slice of flexible array member of length `len`.
get_slice(&self, len: usize) -> &[S]77     fn get_slice(&self, len: usize) -> &[S];
78     /// Implementations must return a mutable slice of flexible array member of length `len`.
get_mut_slice(&mut self, len: usize) -> &mut [S]79     fn get_mut_slice(&mut self, len: usize) -> &mut [S];
80 }
81 
82 pub struct FlexibleArrayWrapper<T, S> {
83     entries: Vec<T>,
84     phantom: PhantomData<S>,
85     allocated_len: usize,
86 }
87 
88 /// Convenience wrapper for flexible array structs.
89 ///
90 /// The FlexibleArray trait must be implemented for the flexible array struct before using this
91 /// wrapper.
92 impl<T, S> FlexibleArrayWrapper<T, S>
93 where
94     T: FlexibleArray<S> + Default,
95 {
96     /// Creates a new FlexibleArrayWrapper for the given flexible array struct type and flexible
97     /// array type. The flexible array length is set to `array_len`. vec_with_array_field is used
98     /// to make sure the resultant wrapper is appropriately sized.
new(array_len: usize) -> FlexibleArrayWrapper<T, S>99     pub fn new(array_len: usize) -> FlexibleArrayWrapper<T, S> {
100         let mut entries = vec_with_array_field::<T, S>(array_len);
101         entries[0].set_len(array_len);
102 
103         FlexibleArrayWrapper {
104             entries,
105             phantom: PhantomData,
106             allocated_len: array_len,
107         }
108     }
109 
110     /// Mapping the unsized array to a slice is unsafe because the length isn't known.  Using
111     /// the length we originally allocated with eliminates the possibility of overflow.
get_valid_len(&self) -> usize112     fn get_valid_len(&self) -> usize {
113         if self.entries[0].get_len() > self.allocated_len {
114             self.allocated_len
115         } else {
116             self.entries[0].get_len()
117         }
118     }
119 
120     /// Returns a slice of the flexible array member, for inspecting. To modify, use
121     /// mut_entries_slice instead.
entries_slice(&self) -> &[S]122     pub fn entries_slice(&self) -> &[S] {
123         let valid_length = self.get_valid_len();
124         self.entries[0].get_slice(valid_length)
125     }
126 
127     /// Returns a mutable slice of the flexible array member, for modifying.
mut_entries_slice(&mut self) -> &mut [S]128     pub fn mut_entries_slice(&mut self) -> &mut [S] {
129         let valid_length = self.get_valid_len();
130         self.entries[0].set_len(valid_length);
131         self.entries[0].get_mut_slice(valid_length)
132     }
133 
134     /// Get a pointer so it can be passed to the kernel. Callers must not access the flexible
135     /// array member.  Using this pointer is unsafe.
as_ptr(&self) -> *const T136     pub fn as_ptr(&self) -> *const T {
137         &self.entries[0]
138     }
139 
140     /// Get a mutable pointer so it can be passed to the kernel. Callers must not access the
141     /// flexible array member.  Using this pointer is unsafe.
as_mut_ptr(&mut self) -> *mut T142     pub fn as_mut_ptr(&mut self) -> *mut T {
143         &mut self.entries[0]
144     }
145 }
146