il2_utils/vec/
mod.rs

1/*
2 * BSD 3-Clause License
3 *
4 * Copyright (c) 2019-2020, InterlockLedger Network
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice, this
11 *   list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above copyright notice,
14 *   this list of conditions and the following disclaimer in the documentation
15 *   and/or other materials provided with the distribution.
16 *
17 * * Neither the name of the copyright holder nor the names of its
18 *   contributors may be used to endorse or promote products derived from
19 *   this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32//! This module implements utilities to handle [`std::vec::Vec`]. Most of those
33//! utilities are optimized for fast memory manipulations whenever possible.
34//!
35//! It is important to notice that some methods and functions inside this
36//! package rely on unsafe code to achieve maximum performance.
37#[cfg(test)]
38mod tests;
39
40use zeroize::Zeroize;
41
42//=============================================================================
43// VecExtensions
44//-----------------------------------------------------------------------------
45/// This trait adds some extension methods to [`std::vec::Vec`] for primitive
46/// types like integers, floating points and booleans.
47///
48/// Most of those extensions are designed to be either fast implementations of
49/// existing methods or secure versions of them.
50///
51/// ## Safety
52///
53/// Some operations performed by this extension relies heavily on pointer
54/// operations and bitwise copies (see [`std::ptr`] for further details).
55/// Because of that, it is not safe to implement this trait for non primitive
56/// types because it may lead to memory safety violations and potential double
57/// free situations.
58///
59/// ## Secure variants
60///
61/// This extension also include secure variants of some of the vector methods.
62/// Those variants always zeroes the memory segments before releasing them back
63/// to the memory pool.
64///
65/// Logically, they do perform the same operations but they are way more
66/// expensive than their regular versions. We recommend the use of those
67/// versions if and only if you need to avoid potential confidential data
68/// leak to the system.
69///
70/// It is possible that, when the **allocator_api**
71/// [#32838](https://github.com/rust-lang/rust/issues/32838) become fully
72/// integrated into the standard API, those methods will no longer be
73/// necessary as the proper memory cleanup will be done by an
74/// [`std::alloc::Allocator`] instead of the hacks used by those methods.
75pub trait VecExtensions<T: Copy + Sized>: Zeroize {
76    /// Creates a new vector already initialized with the specified value.
77    ///
78    /// Since it is the first allocation, there is no need to have a secure version
79    /// of this constructor.
80    ///
81    /// Arguments:
82    /// - `value`: The initial value of the new Vec instance, the elements of this
83    /// slice are copied into the new vector;
84    fn with_value(value: &[T]) -> Vec<T>;
85
86    /// This method sets the capacity of the given Vec<u8> to hold at least the
87    /// specified amount of entries. It is similar to [`Vec<u8>::reserve()`] but it
88    /// takes the target capacity insted of an additional capacity.
89    ///
90    /// If the current capacity is equal or larger than the required capacity,
91    /// this method does nothing.
92    ///
93    /// Arguments:
94    /// - `capacity`: The new capacity;
95    fn set_capacity_to(&mut self, capacity: usize);
96
97    /// This method is the secure variant of [`Self::set_capacity_to()`].
98    ///
99    /// Arguments:
100    /// - `capacity`: The new capacity;
101    fn set_capacity_to_secure(&mut self, capacity: usize);
102
103    /// Replaces the contents of this vector with the contents of a given
104    /// slice. It will expand the size of this vector as needed but will
105    /// never shrink it.
106    ///
107    /// Arguments:
108    /// - `other`: The new capacity;
109    fn set_contents_from_slice(&mut self, other: &[T]);
110
111    /// This method is the secure variant of [`Self::set_contents_from_slice()`].
112    ///
113    /// Arguments:
114    /// - `other`: The new capacity;
115    fn set_contents_from_slice_secure(&mut self, other: &[T]);
116
117    /// This method is the secure version of [`std::vec::Vec::shrink_to_fit()`].
118    fn shrink_to_fit_secure(&mut self);
119
120    /// This method is the secure version of [`std::vec::Vec::reserve()`].
121    fn reserve_secure(&mut self, additional: usize);
122
123    /// This method is the secure version of [`std::vec::Vec::extend_from_slice()`].
124    fn extend_from_slice_secure(&mut self, other: &[T]);
125}
126
127macro_rules! vecextention_base_impl {
128    ($type: ty) => {
129        impl VecExtensions<$type> for Vec<$type> {
130            fn with_value(value: &[$type]) -> Vec<$type> {
131                let mut obj = Vec::with_capacity(value.len());
132                obj.set_contents_from_slice(value);
133                obj
134            }
135
136            fn set_capacity_to(&mut self, capacity: usize) {
137                let curr_capacity = self.capacity();
138                if curr_capacity < capacity {
139                    self.reserve(capacity - self.len());
140                }
141            }
142
143            fn set_capacity_to_secure(&mut self, capacity: usize) {
144                let curr_capacity = self.capacity();
145                if curr_capacity < capacity {
146                    if self.is_empty() {
147                        // No data to move, just adjust the capacity
148                        self.zeroize();
149                        self.set_capacity_to(capacity);
150                    } else if curr_capacity < capacity {
151                        // Copy the values into a temporary buffer before resizing
152                        // because it is not possible to ensure that the original
153                        // buffer will not be replaced by a larger one. If this happens,
154                        // the original data will be released to the memory pool with its
155                        // contents intact and this is exactly what we are trying to avoid.
156                        let mut tmp: Vec<$type> = Vec::with_capacity(self.len());
157                        tmp.set_contents_from_slice(self.as_slice());
158                        // Zeroize the original vector before resizing, also set its
159                        // size to zero to avoid unecessary copy operation while resizing.
160                        self.zeroize();
161                        self.truncate(0);
162                        // Sets the new capacity
163                        self.set_capacity_to(capacity);
164                        // Copy the values back into the original vector
165                        assert!(self.capacity() >= tmp.len());
166                        unsafe {
167                            std::ptr::copy_nonoverlapping(
168                                tmp.as_ptr(),
169                                self.as_mut_ptr(),
170                                tmp.len(),
171                            );
172                            self.set_len(tmp.len());
173                        }
174                        // Clear the temporay copy...
175                        tmp.zeroize();
176                    }
177                }
178            }
179
180            fn set_contents_from_slice(&mut self, other: &[$type]) {
181                self.set_capacity_to(other.len());
182                unsafe {
183                    self.set_len(other.len());
184                    std::ptr::copy_nonoverlapping(other.as_ptr(), self.as_mut_ptr(), other.len());
185                }
186            }
187
188            fn set_contents_from_slice_secure(&mut self, other: &[$type]) {
189                self.zeroize();
190                self.reserve(other.len());
191                unsafe {
192                    self.set_len(other.len());
193                    std::ptr::copy_nonoverlapping(other.as_ptr(), self.as_mut_ptr(), other.len());
194                }
195            }
196
197            fn shrink_to_fit_secure(&mut self) {
198                // Copy to a temporary value
199                let mut tmp: Vec<$type> = Vec::with_capacity(self.len());
200                tmp.set_contents_from_slice(self.as_slice());
201                // Clear the old data and shrink
202                self.zeroize();
203                self.shrink_to_fit();
204                // Copy the contents back into the array.
205                self.set_contents_from_slice(tmp.as_slice());
206                // Clear the temporary buffer
207                tmp.zeroize();
208            }
209
210            fn reserve_secure(&mut self, additional: usize) {
211                self.set_capacity_to_secure(self.len() + additional);
212            }
213
214            fn extend_from_slice_secure(&mut self, other: &[$type]) {
215                self.reserve_secure(other.len());
216                assert!(self.capacity() >= self.len() + other.len());
217                unsafe {
218                    std::ptr::copy_nonoverlapping(
219                        other.as_ptr(),
220                        self.as_mut_ptr().add(self.len()),
221                        other.len(),
222                    );
223                    self.set_len(self.len() + other.len());
224                }
225            }
226        }
227    };
228}
229
230macro_rules! multi_vecextention_base_impl {
231    ($type: ty) => {
232        vecextention_base_impl!($type);
233    };
234    ($type: ty, $($type2: ty), +) => {
235        vecextention_base_impl! ($type);
236        multi_vecextention_base_impl!($($type2), +);
237    };
238}
239
240multi_vecextention_base_impl!(bool);
241multi_vecextention_base_impl!(u8, u16, u32, u64, u128);
242multi_vecextention_base_impl!(i8, i16, i32, i64, i128);
243multi_vecextention_base_impl!(f32, f64);