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