secure_types/
vec.rs

1#[cfg(not(feature = "use_os"))]
2use alloc::{Layout, alloc, dealloc};
3
4#[cfg(feature = "use_os")]
5use std::vec::Vec;
6
7use super::{Error, SecureArray};
8use core::{
9   marker::PhantomData,
10   mem,
11   ops::{Bound, RangeBounds},
12   ptr::{self, NonNull},
13};
14use zeroize::{DefaultIsZeroes, Zeroize};
15
16#[cfg(feature = "use_os")]
17use super::{alloc_aligned, free, page_aligned_size};
18#[cfg(feature = "use_os")]
19use memsec::Prot;
20
21pub type SecureBytes = SecureVec<u8>;
22
23/// A securely allocated, growable vector, just like `std::vec::Vec`.
24///
25/// ## Security Model
26///
27/// When compiled with the `use_os` feature (the default), it provides several layers of protection:
28/// - **Zeroization on Drop**: The memory is zeroized when the vector is dropped.
29/// - **Memory Locking**: The underlying memory pages are locked using `mlock` & `madvise` for (Unix) or
30///   `VirtualLock` & `VirtualProtect` for (Windows) to prevent the OS from memory-dump/swap to disk or other processes accessing the memory.
31/// - **Memory Encryption**: On Windows, the memory is also encrypted using `CryptProtectMemory`.
32///
33/// In a `no_std` environment, it falls back to providing only the **zeroization-on-drop** guarantee.
34///
35/// ## Program Termination
36///
37/// Direct indexing (e.g., `vec[0]`) on a locked vector will cause the operating system
38/// to terminate the process with an access violation error.
39///
40/// Always use the provided scope methods (`unlock_slice`, `unlock_slice_mut`) for safe access.
41///
42/// # Notes
43///
44/// If you return a new allocated `Vec` from one of the unlock methods you are responsible for zeroizing the memory.
45///
46/// # Example
47///
48/// Using `SecureBytes` (a type alias for `SecureVec<u8>`) to handle a secret key.
49///
50/// ```
51/// use secure_types::{SecureBytes, Zeroize};
52///
53/// // Create a new, empty secure vector.
54/// let mut secret_key = SecureBytes::new().unwrap();
55///
56/// // Push some sensitive data into it.
57/// secret_key.push(0xAB);
58/// secret_key.push(0xCD);
59/// secret_key.push(0xEF);
60///
61/// // The memory is locked here.
62///
63/// // Use a scope to safely access the contents as a slice.
64/// secret_key.unlock_slice(|unlocked_slice| {
65///     assert_eq!(unlocked_slice, &[0xAB, 0xCD, 0xEF]);
66/// });
67///
68/// // Not recommended but if you allocate a new Vec make sure to zeroize it
69/// let mut exposed = secret_key.unlock_slice(|unlocked_slice| {
70///     Vec::from(unlocked_slice)
71/// });
72///
73/// // Do what you need to to do with the new vector
74/// // When you are done with it, zeroize it
75/// exposed.zeroize();
76///
77/// // The memory is automatically locked again when the scope ends.
78///
79/// // When `secret_key` is dropped, its memory is securely zeroized.
80/// ```
81pub struct SecureVec<T>
82where
83   T: Zeroize,
84{
85   ptr: NonNull<T>,
86   pub(crate) len: usize,
87   pub(crate) capacity: usize,
88   _marker: PhantomData<T>,
89}
90
91unsafe impl<T: Zeroize + Send> Send for SecureVec<T> {}
92unsafe impl<T: Zeroize + Send + Sync> Sync for SecureVec<T> {}
93
94impl<T: Zeroize> SecureVec<T> {
95   /// Create a new `SecureVec` with a capacity of 1
96   pub fn new() -> Result<Self, Error> {
97      // Give at least a capacity of 1 so encryption/decryption can be done.
98      let capacity = 1;
99      let size = capacity * mem::size_of::<T>();
100      let ptr = unsafe { alloc_aligned::<T>(size)? };
101
102      let secure = SecureVec {
103         ptr,
104         len: 0,
105         capacity,
106         _marker: PhantomData,
107      };
108
109      let (encrypted, locked) = secure.lock_memory();
110
111      #[cfg(feature = "use_os")]
112      if !locked {
113         return Err(Error::LockFailed);
114      }
115
116      #[cfg(feature = "use_os")]
117      if !encrypted {
118         return Err(Error::CryptProtectMemoryFailed);
119      }
120
121      Ok(secure)
122   }
123
124   /// Create a new `SecureVec` with the given capacity
125   pub fn new_with_capacity(mut capacity: usize) -> Result<Self, Error> {
126      if capacity == 0 {
127         capacity = 1;
128      }
129
130      let size = capacity * mem::size_of::<T>();
131      let ptr = unsafe { alloc_aligned::<T>(size)? };
132
133      let secure = SecureVec {
134         ptr,
135         len: 0,
136         capacity,
137         _marker: PhantomData,
138      };
139
140      let (encrypted, locked) = secure.lock_memory();
141
142      #[cfg(feature = "use_os")]
143      if !locked {
144         return Err(Error::LockFailed);
145      }
146
147      #[cfg(feature = "use_os")]
148      if !encrypted {
149         return Err(Error::CryptProtectMemoryFailed);
150      }
151
152      Ok(secure)
153   }
154
155   #[cfg(feature = "use_os")]
156   /// Create a new `SecureVec` from a `Vec`
157   ///
158   /// The `Vec` is zeroized afterwards
159   pub fn from_vec(mut vec: Vec<T>) -> Result<Self, Error> {
160      if vec.capacity() == 0 {
161         vec.reserve(1);
162      }
163
164      let capacity = vec.capacity();
165      let len = vec.len();
166
167      let size = capacity * mem::size_of::<T>();
168
169      let ptr = match unsafe { alloc_aligned::<T>(size) } {
170         Ok(ptr) => ptr,
171         Err(_) => {
172            vec.zeroize();
173            return Err(Error::AllocationFailed);
174         }
175      };
176
177      // Copy data from the old pointer to the new one
178      unsafe {
179         core::ptr::copy_nonoverlapping(vec.as_ptr(), ptr.as_ptr() as *mut T, len);
180      }
181
182      vec.zeroize();
183
184      let secure = SecureVec {
185         ptr,
186         len,
187         capacity,
188         _marker: PhantomData,
189      };
190
191      let (encrypted, locked) = secure.lock_memory();
192
193      if !locked {
194         return Err(Error::LockFailed);
195      }
196
197      if !encrypted {
198         return Err(Error::CryptProtectMemoryFailed);
199      }
200
201      Ok(secure)
202   }
203
204   /// Create a new `SecureVec` from a mutable slice.
205   ///
206   /// The slice is zeroized afterwards
207   pub fn from_slice_mut(slice: &mut [T]) -> Result<Self, Error>
208   where
209      T: Clone + DefaultIsZeroes,
210   {
211      let mut secure_vec = SecureVec::new_with_capacity(slice.len())?;
212      secure_vec.len = slice.len();
213      secure_vec.unlock_slice_mut(|dest_slice| {
214         dest_slice.clone_from_slice(slice);
215      });
216      slice.zeroize();
217      Ok(secure_vec)
218   }
219
220   /// Create a new `SecureVec` from a slice.
221   ///
222   /// The slice is not zeroized, you are responsible for zeroizing it
223   pub fn from_slice(slice: &[T]) -> Result<Self, Error>
224   where
225      T: Clone,
226   {
227      let mut secure_vec = SecureVec::new_with_capacity(slice.len())?;
228      secure_vec.len = slice.len();
229      secure_vec.unlock_slice_mut(|dest_slice| {
230         dest_slice.clone_from_slice(slice);
231      });
232      Ok(secure_vec)
233   }
234
235   pub fn len(&self) -> usize {
236      self.len
237   }
238
239   pub fn is_empty(&self) -> bool {
240      self.len() == 0
241   }
242
243   pub fn as_ptr(&self) -> *const T {
244      self.ptr.as_ptr()
245   }
246
247   pub fn as_mut_ptr(&mut self) -> *mut u8 {
248      self.ptr.as_ptr() as *mut u8
249   }
250
251   #[allow(dead_code)]
252   fn aligned_size(&self) -> usize {
253      let size = self.capacity * mem::size_of::<T>();
254      #[cfg(feature = "use_os")]
255      {
256         unsafe { page_aligned_size(size) }
257      }
258      #[cfg(not(feature = "use_os"))]
259      {
260         size // No page alignment in no_std
261      }
262   }
263
264   #[cfg(all(feature = "use_os", windows))]
265   fn encypt_memory(&self) -> bool {
266      let ptr = self.as_ptr() as *mut u8;
267      super::crypt_protect_memory(ptr, self.aligned_size())
268   }
269
270   #[cfg(all(feature = "use_os", windows))]
271   fn decrypt_memory(&self) -> bool {
272      let ptr = self.as_ptr() as *mut u8;
273      super::crypt_unprotect_memory(ptr, self.aligned_size())
274   }
275
276   pub(crate) fn lock_memory(&self) -> (bool, bool) {
277      #[cfg(feature = "use_os")]
278      {
279         #[cfg(windows)]
280         {
281            let encrypt_ok = self.encypt_memory();
282            let mprotect_ok = super::mprotect(self.ptr, Prot::NoAccess);
283            (encrypt_ok, mprotect_ok)
284         }
285         #[cfg(unix)]
286         {
287            let mprotect_ok = super::mprotect(self.ptr, Prot::NoAccess);
288            (true, mprotect_ok)
289         }
290      }
291      #[cfg(not(feature = "use_os"))]
292      {
293         (true, true) // No-op: always "succeeds"
294      }
295   }
296
297   pub(crate) fn unlock_memory(&self) -> (bool, bool) {
298      #[cfg(feature = "use_os")]
299      {
300         #[cfg(windows)]
301         {
302            let mprotect_ok = super::mprotect(self.ptr, Prot::ReadWrite);
303            if !mprotect_ok {
304               return (false, false);
305            }
306            let decrypt_ok = self.decrypt_memory();
307            (decrypt_ok, mprotect_ok)
308         }
309         #[cfg(unix)]
310         {
311            let mprotect_ok = super::mprotect(self.ptr, Prot::ReadWrite);
312            (true, mprotect_ok)
313         }
314      }
315
316      #[cfg(not(feature = "use_os"))]
317      {
318         (true, true) // No-op: always "succeeds"
319      }
320   }
321
322   /// Immutable access to the `SecureVec`
323   pub fn unlock<F, R>(&self, f: F) -> R
324   where
325      F: FnOnce(&SecureVec<T>) -> R,
326   {
327      self.unlock_memory();
328      let result = f(self);
329      self.lock_memory();
330      result
331   }
332
333   /// Immutable access to the `SecureVec` as `&[T]`
334   pub fn unlock_slice<F, R>(&self, f: F) -> R
335   where
336      F: FnOnce(&[T]) -> R,
337   {
338      unsafe {
339         self.unlock_memory();
340         let slice = core::slice::from_raw_parts(self.ptr.as_ptr(), self.len);
341         let result = f(slice);
342         self.lock_memory();
343         result
344      }
345   }
346
347   /// Mutable access to the `SecureVec` as `&mut [T]`
348   pub fn unlock_slice_mut<F, R>(&mut self, f: F) -> R
349   where
350      F: FnOnce(&mut [T]) -> R,
351   {
352      unsafe {
353         self.unlock_memory();
354         let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
355         let result = f(slice);
356         self.lock_memory();
357         result
358      }
359   }
360
361   /// Immutable access to the `SecureVec` as `Iter<T>`
362   pub fn unlock_iter<F, R>(&self, f: F) -> R
363   where
364      F: FnOnce(core::slice::Iter<T>) -> R,
365   {
366      unsafe {
367         self.unlock_memory();
368         let slice = core::slice::from_raw_parts(self.ptr.as_ptr(), self.len);
369         let iter = slice.iter();
370         let result = f(iter);
371         self.lock_memory();
372         result
373      }
374   }
375
376   /// Mutable access to the `SecureVec` as `IterMut<T>`
377   pub fn unlock_iter_mut<F, R>(&mut self, f: F) -> R
378   where
379      F: FnOnce(core::slice::IterMut<T>) -> R,
380   {
381      unsafe {
382         self.unlock_memory();
383         let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
384         let iter = slice.iter_mut();
385         let result = f(iter);
386         self.lock_memory();
387         result
388      }
389   }
390
391   /// Erase the underlying data and clears the vector
392   ///
393   /// The memory is locked again and the capacity is preserved for reuse
394   pub fn erase(&mut self) {
395      unsafe {
396         self.unlock_memory();
397         let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
398         for elem in slice.iter_mut() {
399            elem.zeroize();
400         }
401         self.clear();
402         self.lock_memory();
403      }
404   }
405
406   /// Clear the vector
407   ///
408   /// This just sets the vector's len to zero it does not erase the underlying data
409   pub fn clear(&mut self) {
410      self.len = 0;
411   }
412
413   pub fn push(&mut self, value: T) {
414      self.reserve(1);
415
416      self.unlock_memory();
417
418      unsafe {
419         // Write the new value at the end of the vector.
420         core::ptr::write(self.ptr.as_ptr().add(self.len), value);
421
422         self.len += 1;
423      }
424
425      self.lock_memory();
426   }
427
428   /// Ensures that the vector has enough capacity for at least `additional` more elements.
429   ///
430   /// If more capacity is needed, it will reallocate. This may cause the buffer location to change.
431   ///
432   /// # Panics
433   ///
434   /// Panics if the new capacity overflows `usize` or if the allocation fails.
435   pub fn reserve(&mut self, additional: usize) {
436      if self.len() + additional <= self.capacity {
437         return;
438      }
439
440      // Use an amortized growth strategy to avoid reallocating on every push
441      let required_capacity = self.len() + additional;
442      let new_capacity = (self.capacity.max(1) * 2).max(required_capacity);
443
444      let new_size = new_capacity * mem::size_of::<T>();
445      let new_ptr = unsafe { alloc_aligned::<T>(new_size).expect("Allocation failed") };
446
447      // Copy data to new pointer
448      unsafe {
449         self.unlock_memory();
450         core::ptr::copy_nonoverlapping(
451            self.ptr.as_ptr(),
452            new_ptr.as_ptr() as *mut T,
453            self.len(),
454         );
455
456         // Erase and free the old memory
457         if self.capacity > 0 {
458            let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
459            for elem in slice.iter_mut() {
460               elem.zeroize();
461            }
462         }
463
464         #[cfg(feature = "use_os")]
465         free(self.ptr);
466
467         #[cfg(not(feature = "use_os"))]
468         {
469            let old_size = self.capacity * mem::size_of::<T>();
470            let old_layout = Layout::from_size_align_unchecked(old_size, mem::align_of::<T>());
471            dealloc(self.ptr.as_ptr() as *mut u8, old_layout);
472         }
473      }
474
475      // Update pointer and capacity, then re-lock the new memory region
476      self.ptr = new_ptr;
477      self.capacity = new_capacity;
478      self.lock_memory();
479   }
480
481   /// Creates a draining iterator that removes the specified range from the vector
482   /// and yields the removed items.
483   ///
484   /// Note: The vector is unlocked during the lifetime of the `Drain` iterator.
485   /// The memory is relocked when the `Drain` iterator is dropped.
486   ///
487   /// # Panics
488   /// Panics if the starting point is greater than the end point or if the end point
489   /// is greater than the length of the vector.
490   pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
491   where
492      R: RangeBounds<usize>,
493   {
494      self.unlock_memory();
495
496      let original_len = self.len;
497
498      let (drain_start_idx, drain_end_idx) = resolve_range_indices(range, original_len);
499
500      let tail_len = original_len - drain_end_idx;
501
502      self.len = drain_start_idx;
503
504      Drain {
505         vec_ref: self,
506         drain_start_index: drain_start_idx,
507         current_drain_iter_index: drain_start_idx,
508         drain_end_index: drain_end_idx,
509         original_vec_len: original_len,
510         tail_len,
511         _marker: PhantomData,
512      }
513   }
514}
515
516impl<T: Clone + Zeroize> Clone for SecureVec<T> {
517   fn clone(&self) -> Self {
518      let mut new_vec = SecureVec::new_with_capacity(self.capacity).unwrap();
519      new_vec.len = self.len;
520
521      self.unlock_slice(|src_slice| {
522         new_vec.unlock_slice_mut(|dest_slice| {
523            dest_slice.clone_from_slice(src_slice);
524         });
525      });
526
527      new_vec
528   }
529}
530
531impl<const LENGTH: usize> From<SecureArray<u8, LENGTH>> for SecureVec<u8> {
532   fn from(array: SecureArray<u8, LENGTH>) -> Self {
533      let mut new_vec = SecureVec::new_with_capacity(LENGTH)
534         .expect("Failed to allocate SecureVec during conversion");
535      new_vec.len = array.len();
536
537      array.unlock(|array_slice| {
538         new_vec.unlock_slice_mut(|vec_slice| {
539            vec_slice.copy_from_slice(array_slice);
540         });
541      });
542
543      new_vec
544   }
545}
546
547impl<T: Zeroize> Drop for SecureVec<T> {
548   fn drop(&mut self) {
549      self.erase();
550      self.unlock_memory();
551
552      #[cfg(feature = "use_os")]
553      free(self.ptr);
554
555      #[cfg(not(feature = "use_os"))]
556      {
557         let layout =
558            Layout::from_size_align_unchecked(self.allocated_byte_size(), mem::align_of::<T>());
559         dealloc(self.ptr.as_ptr() as *mut u8, layout);
560      }
561   }
562}
563
564impl<T: Zeroize> core::ops::Index<usize> for SecureVec<T> {
565   type Output = T;
566
567   fn index(&self, index: usize) -> &Self::Output {
568      assert!(index < self.len, "Index out of bounds");
569      unsafe {
570         let ptr = self.ptr.as_ptr().add(index);
571         &*ptr
572      }
573   }
574}
575
576#[cfg(feature = "serde")]
577impl serde::Serialize for SecureVec<u8> {
578   fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
579   where
580      S: serde::Serializer,
581   {
582      self.unlock_slice(|slice| serializer.collect_seq(slice.iter()))
583   }
584}
585
586#[cfg(feature = "serde")]
587impl<'de> serde::Deserialize<'de> for SecureVec<u8> {
588   fn deserialize<D>(deserializer: D) -> Result<SecureVec<u8>, D::Error>
589   where
590      D: serde::Deserializer<'de>,
591   {
592      struct SecureVecVisitor;
593      impl<'de> serde::de::Visitor<'de> for SecureVecVisitor {
594         type Value = SecureVec<u8>;
595         fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
596            write!(formatter, "a sequence of bytes")
597         }
598         fn visit_seq<A>(
599            self,
600            mut seq: A,
601         ) -> Result<<Self as serde::de::Visitor<'de>>::Value, A::Error>
602         where
603            A: serde::de::SeqAccess<'de>,
604         {
605            let mut vec = Vec::new();
606            while let Some(byte) = seq.next_element::<u8>()? {
607               vec.push(byte);
608            }
609            SecureVec::from_vec(vec).map_err(serde::de::Error::custom)
610         }
611      }
612      deserializer.deserialize_seq(SecureVecVisitor)
613   }
614}
615
616/// A draining iterator for `SecureVec<T>`.
617///
618/// This struct is created by the `drain` method on `SecureVec`.
619///
620/// # Safety
621/// The returned `Drain` iterator must not be forgotten (via `mem::forget`).
622/// Forgetting the iterator sets the len of `SecureVec` to 0 and the memory will remain unlocked
623pub struct Drain<'a, T: Zeroize + 'a> {
624   vec_ref: &'a mut SecureVec<T>,
625   drain_start_index: usize,
626   current_drain_iter_index: usize,
627   drain_end_index: usize,
628
629   original_vec_len: usize, // Original length of vec_ref before drain
630   tail_len: usize,         // Number of elements after the drain range in the original vec
631
632   _marker: PhantomData<&'a T>,
633}
634
635impl<'a, T: Zeroize> Iterator for Drain<'a, T> {
636   type Item = T;
637
638   fn next(&mut self) -> Option<T> {
639      if self.current_drain_iter_index < self.drain_end_index {
640         // SecureVec is already unlocked by the `drain` method.
641         unsafe {
642            let item_ptr = self.vec_ref.ptr.as_ptr().add(self.current_drain_iter_index);
643            let item = ptr::read(item_ptr);
644            self.current_drain_iter_index += 1;
645            Some(item)
646         }
647      } else {
648         None
649      }
650   }
651
652   fn size_hint(&self) -> (usize, Option<usize>) {
653      let remaining = self.drain_end_index - self.current_drain_iter_index;
654      (remaining, Some(remaining))
655   }
656}
657
658impl<'a, T: Zeroize> ExactSizeIterator for Drain<'a, T> {}
659
660impl<'a, T: Zeroize> Drop for Drain<'a, T> {
661   fn drop(&mut self) {
662      unsafe {
663         // The vec_ref's memory is currently unlocked.
664         if mem::needs_drop::<T>() {
665            let mut current_ptr = self.vec_ref.ptr.as_ptr().add(self.current_drain_iter_index);
666            let end_ptr = self.vec_ref.ptr.as_ptr().add(self.drain_end_index);
667            while current_ptr < end_ptr {
668               ptr::drop_in_place(current_ptr);
669               current_ptr = current_ptr.add(1);
670            }
671         }
672
673         let hole_dst_ptr = self.vec_ref.ptr.as_ptr().add(self.drain_start_index);
674         let tail_src_ptr = self.vec_ref.ptr.as_ptr().add(self.drain_end_index);
675
676         if self.tail_len > 0 {
677            ptr::copy(tail_src_ptr, hole_dst_ptr, self.tail_len);
678         }
679
680         // The new length of the vector.
681         let new_len = self.drain_start_index + self.tail_len;
682
683         // Process the memory region that is no longer part of the active vector's content.
684         // This region is from `vec_ref.ptr + new_len` up to `vec_ref.ptr + original_vec_len`.
685         // It contains:
686         //    a) Original data of the latter part of the drained slice (if not overwritten by tail).
687         //       These were dropped in step 1 if T:Drop.
688         //    b) Original data of the tail items (which have now been copied).
689         //       These need to be dropped if T:Drop, as ptr::copy doesn't drop the source.
690         // After any necessary drops, this entire region must be zeroized.
691
692         let mut current_cleanup_ptr = self.vec_ref.ptr.as_ptr().add(new_len);
693         let end_cleanup_ptr = self.vec_ref.ptr.as_ptr().add(self.original_vec_len);
694
695         // Determine the start of the original tail's memory region
696         let original_tail_start_ptr_val = tail_src_ptr as usize;
697
698         while current_cleanup_ptr < end_cleanup_ptr {
699            if mem::needs_drop::<T>() {
700               let current_ptr_val = current_cleanup_ptr as usize;
701               let original_tail_end_ptr_val =
702                  original_tail_start_ptr_val + self.tail_len * mem::size_of::<T>();
703
704               if current_ptr_val >= original_tail_start_ptr_val
705                  && current_ptr_val < original_tail_end_ptr_val
706               {
707                  // This element was part of the original tail. ptr::copy moved its value.
708                  // The original instance here needs to be dropped.
709                  ptr::drop_in_place(current_cleanup_ptr);
710               }
711               // Else, it was part of the drained range (not covered by tail move).
712               // If it needed dropping, it was handled in step 1.
713            }
714
715            // Zeroize the memory of this element.
716            (*current_cleanup_ptr).zeroize();
717            current_cleanup_ptr = current_cleanup_ptr.add(1);
718         }
719
720         // Update the SecureVec's length.
721         self.vec_ref.len = new_len;
722
723         // Relock the SecureVec's memory.
724         self.vec_ref.lock_memory();
725      }
726   }
727}
728
729// Helper function to resolve RangeBounds to (start, end) indices
730fn resolve_range_indices<R: RangeBounds<usize>>(range: R, len: usize) -> (usize, usize) {
731   let start_bound = range.start_bound();
732   let end_bound = range.end_bound();
733
734   let start = match start_bound {
735      Bound::Included(&s) => s,
736      Bound::Excluded(&s) => s
737         .checked_add(1)
738         .unwrap_or_else(|| panic!("attempted to start drain at Excluded(usize::MAX)")),
739      Bound::Unbounded => 0,
740   };
741
742   let end = match end_bound {
743      Bound::Included(&e) => e
744         .checked_add(1)
745         .unwrap_or_else(|| panic!("attempted to end drain at Included(usize::MAX)")),
746      Bound::Excluded(&e) => e,
747      Bound::Unbounded => len,
748   };
749
750   if start > end {
751      panic!(
752         "drain range start ({}) must be less than or equal to end ({})",
753         start, end
754      );
755   }
756   if end > len {
757      panic!(
758         "drain range end ({}) out of bounds for slice of length {}",
759         end, len
760      );
761   }
762
763   (start, end)
764}
765
766#[cfg(all(test, feature = "use_os"))]
767mod tests {
768   use super::*;
769   use std::process::{Command, Stdio};
770   use std::sync::{Arc, Mutex};
771
772   #[test]
773   fn test_creation() {
774      let vec: Vec<u8> = vec![1, 2, 3];
775      let secure_vec = SecureVec::from_vec(vec).unwrap();
776
777      secure_vec.unlock_slice(|slice| {
778         assert_eq!(slice, &[1, 2, 3]);
779      });
780
781      let exposed_slice = &mut [1, 2, 3];
782      let secure_slice = SecureVec::from_slice_mut(exposed_slice).unwrap();
783      assert_eq!(exposed_slice, &[0u8; 3]);
784
785      secure_slice.unlock_slice(|slice| {
786         assert_eq!(slice, &[1, 2, 3]);
787      });
788
789      let exposed_slice = [1, 2, 3];
790      let secure_slice = SecureVec::from_slice(&exposed_slice).unwrap();
791
792      secure_slice.unlock_slice(|slice| {
793         assert_eq!(slice, exposed_slice);
794      });
795   }
796
797   #[test]
798   fn test_from_secure_array() {
799      let exposed: &mut [u8; 3] = &mut [1, 2, 3];
800      let array: SecureArray<u8, 3> = SecureArray::from_slice_mut(exposed).unwrap();
801      let vec: SecureVec<u8> = array.into();
802      assert_eq!(vec.len(), 3);
803      vec.unlock_slice(|slice| {
804         assert_eq!(slice, &[1, 2, 3]);
805      });
806   }
807
808   #[test]
809   fn test_size_cannot_be_zero() {
810      let secure: SecureVec<u8> = SecureVec::new().unwrap();
811      let size = secure.aligned_size();
812      assert_eq!(size > 0, true);
813
814      let secure: SecureVec<u8> = SecureVec::from_vec(vec![]).unwrap();
815      let size = secure.aligned_size();
816      assert_eq!(size > 0, true);
817
818      let secure: SecureVec<u8> = SecureVec::new_with_capacity(0).unwrap();
819      let size = secure.aligned_size();
820      assert_eq!(size > 0, true);
821   }
822
823   #[test]
824   fn lock_unlock_works() {
825      let secure: SecureVec<u8> = SecureVec::new().unwrap();
826
827      let (decrypted, unlocked) = secure.unlock_memory();
828      assert!(decrypted);
829      assert!(unlocked);
830
831      let (encrypted, locked) = secure.lock_memory();
832      assert!(encrypted);
833      assert!(locked);
834   }
835
836   #[test]
837   fn test_thread_safety() {
838      let vec: Vec<u8> = vec![];
839      let secure = SecureVec::from_vec(vec).unwrap();
840      let secure = Arc::new(Mutex::new(secure));
841
842      let mut handles = Vec::new();
843      for i in 0..5u8 {
844         let secure_clone = secure.clone();
845         let handle = std::thread::spawn(move || {
846            let mut secure = secure_clone.lock().unwrap();
847            secure.push(i);
848         });
849         handles.push(handle);
850      }
851
852      for handle in handles {
853         handle.join().unwrap();
854      }
855
856      let mut sec = secure.lock().unwrap();
857      sec.unlock_slice_mut(|slice| {
858         slice.sort();
859         assert_eq!(slice.len(), 5);
860         assert_eq!(slice, &[0, 1, 2, 3, 4]);
861      });
862   }
863
864   #[test]
865   fn test_clone() {
866      let vec: Vec<u8> = vec![1, 2, 3];
867      let secure1 = SecureVec::from_vec(vec).unwrap();
868      let secure2 = secure1.clone();
869
870      secure1.unlock_slice(|slice| {
871         secure2.unlock_slice(|slice2| {
872            assert_eq!(slice, slice2);
873         });
874      });
875   }
876
877   #[test]
878   fn test_do_not_call_forget_on_drain() {
879      let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
880      let mut secure = SecureVec::from_vec(vec).unwrap();
881      let drain = secure.drain(..3);
882      core::mem::forget(drain);
883      // we can still use secure vec but its state is unreachable
884      secure.unlock_slice(|secure| {
885         assert_eq!(secure.len(), 0);
886      });
887   }
888
889   #[test]
890   fn test_drain() {
891      let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
892      let mut secure = SecureVec::from_vec(vec).unwrap();
893      let mut drain = secure.drain(..3);
894      assert_eq!(drain.next(), Some(1));
895      assert_eq!(drain.next(), Some(2));
896      assert_eq!(drain.next(), Some(3));
897      assert_eq!(drain.next(), None);
898      drop(drain);
899      secure.unlock_slice(|secure| {
900         assert_eq!(secure.len(), 7);
901         assert_eq!(secure, &[4, 5, 6, 7, 8, 9, 10]);
902      });
903   }
904
905   #[cfg(feature = "serde")]
906   #[test]
907   fn test_secure_vec_serde() {
908      let vec: Vec<u8> = vec![1, 2, 3];
909      let secure = SecureVec::from_vec(vec).unwrap();
910      let json = serde_json::to_vec(&secure).expect("Serialization failed");
911      let deserialized: SecureVec<u8> =
912         serde_json::from_slice(&json).expect("Deserialization failed");
913      deserialized.unlock_slice(|slice| {
914         assert_eq!(slice, &[1, 2, 3]);
915      });
916   }
917
918   #[test]
919   fn test_erase() {
920      let vec: Vec<u8> = vec![1, 2, 3];
921      let mut secure = SecureVec::from_vec(vec).unwrap();
922      secure.erase();
923
924      secure.unlock(|secure| {
925         assert_eq!(secure.len, 0);
926         assert_eq!(secure.capacity, 3);
927      });
928
929      secure.unlock_iter(|iter| {
930         for elem in iter {
931            assert_eq!(elem, &0);
932         }
933      });
934   }
935
936   #[test]
937   fn test_push() {
938      let vec: Vec<u8> = Vec::new();
939      let mut secure = SecureVec::from_vec(vec).unwrap();
940      for i in 0..10 {
941         secure.push(i);
942      }
943
944      assert_eq!(secure.len(), 10);
945
946      secure.unlock_slice(|slice| {
947         assert_eq!(slice, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
948      });
949   }
950
951   #[test]
952   fn test_reserve() {
953      let mut secure: SecureVec<u8> = SecureVec::new().unwrap();
954      secure.reserve(10);
955      assert_eq!(secure.capacity, 10);
956   }
957
958   #[test]
959   fn test_reserve_doubling() {
960      let mut secure: SecureVec<u8> = SecureVec::new().unwrap();
961      secure.reserve(10);
962
963      for i in 0..9 {
964         secure.push(i);
965      }
966
967      secure.push(9);
968      assert_eq!(secure.capacity, 10);
969      assert_eq!(secure.len(), 10);
970
971      secure.push(10);
972      assert_eq!(secure.capacity, 20);
973      assert_eq!(secure.len(), 11);
974   }
975
976   #[test]
977   fn test_index() {
978      let vec: Vec<u8> = vec![1, 2, 3];
979      let secure = SecureVec::from_vec(vec).unwrap();
980      secure.unlock(|secure| {
981         assert_eq!(secure[0], 1);
982         assert_eq!(secure[1], 2);
983         assert_eq!(secure[2], 3);
984      });
985   }
986
987   #[test]
988   fn test_unlock_slice() {
989      let vec: Vec<u8> = vec![1, 2, 3];
990      let secure = SecureVec::from_vec(vec).unwrap();
991      secure.unlock_slice(|slice| {
992         assert_eq!(slice, &[1, 2, 3]);
993      });
994   }
995
996   #[test]
997   fn test_unlock_slice_mut() {
998      let vec: Vec<u8> = vec![1, 2, 3];
999      let mut secure = SecureVec::from_vec(vec).unwrap();
1000
1001      secure.unlock_slice_mut(|slice| {
1002         slice[0] = 4;
1003         assert_eq!(slice, &mut [4, 2, 3]);
1004      });
1005   }
1006
1007   #[test]
1008   fn test_unlock_iter() {
1009      let vec: Vec<u8> = vec![1, 2, 3];
1010      let secure = SecureVec::from_vec(vec).unwrap();
1011      let sum: u8 = secure.unlock_iter(|iter| iter.map(|&x| x).sum());
1012
1013      assert_eq!(sum, 6);
1014
1015      let secure: SecureVec<u8> = SecureVec::new_with_capacity(3).unwrap();
1016      let sum: u8 = secure.unlock_iter(|iter| iter.map(|&x| x).sum());
1017
1018      assert_eq!(sum, 0);
1019   }
1020
1021   #[test]
1022   fn test_unlock_iter_mut() {
1023      let vec: Vec<u8> = vec![1, 2, 3];
1024      let mut secure = SecureVec::from_vec(vec).unwrap();
1025      secure.unlock_iter_mut(|iter| {
1026         for elem in iter {
1027            *elem += 1;
1028         }
1029      });
1030
1031      secure.unlock_slice(|slice| {
1032         assert_eq!(slice, &[2, 3, 4]);
1033      });
1034   }
1035
1036   #[test]
1037   fn test_index_should_fail_when_locked() {
1038      let arg = "CRASH_TEST_SECUREVEC_LOCKED";
1039
1040      if std::env::args().any(|a| a == arg) {
1041         let vec: Vec<u8> = vec![1, 2, 3];
1042         let secure = SecureVec::from_vec(vec).unwrap();
1043         let _value = core::hint::black_box(secure[0]);
1044
1045         std::process::exit(1);
1046      }
1047
1048      let child = Command::new(std::env::current_exe().unwrap())
1049         .arg("vec::tests::test_index_should_fail_when_locked")
1050         .arg(arg)
1051         .arg("--nocapture")
1052         .stdout(Stdio::piped())
1053         .stderr(Stdio::piped())
1054         .spawn()
1055         .expect("Failed to spawn child process");
1056
1057      let output = child.wait_with_output().expect("Failed to wait on child");
1058      let status = output.status;
1059
1060      assert!(
1061         !status.success(),
1062         "Process exited successfully with code {:?}, but it should have crashed.",
1063         status.code()
1064      );
1065
1066      #[cfg(unix)]
1067      {
1068         use std::os::unix::process::ExitStatusExt;
1069         let signal = status
1070            .signal()
1071            .expect("Process was not terminated by a signal on Unix.");
1072         assert!(
1073            signal == libc::SIGSEGV || signal == libc::SIGBUS,
1074            "Process terminated with unexpected signal: {}",
1075            signal
1076         );
1077         println!(
1078            "Test passed: Process correctly terminated with signal {}.",
1079            signal
1080         );
1081      }
1082
1083      #[cfg(windows)]
1084      {
1085         const STATUS_ACCESS_VIOLATION: i32 = 0xC0000005_u32 as i32;
1086         assert_eq!(
1087            status.code(),
1088            Some(STATUS_ACCESS_VIOLATION),
1089            "Process exited with unexpected code: {:x?}. Expected STATUS_ACCESS_VIOLATION.",
1090            status.code()
1091         );
1092         eprintln!("Test passed: Process correctly terminated with STATUS_ACCESS_VIOLATION.");
1093      }
1094   }
1095}