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.capacity);
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.capacity);
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 mut secure = SecureVec::new_with_capacity(10).unwrap();
850      for i in 0..9 {
851         secure.push(i);
852      }
853
854      secure.erase();
855
856      secure.unlock(|secure| {
857         assert_eq!(secure.len, 0);
858         assert_eq!(secure.capacity, 10);
859      });
860
861      secure.unlock_iter(|iter| {
862         for elem in iter {
863            assert_eq!(elem, &0);
864         }
865      });
866   }
867
868   #[test]
869   fn test_push() {
870      let vec: Vec<u8> = Vec::new();
871      let mut secure = SecureVec::from_vec(vec).unwrap();
872      for i in 0..10 {
873         secure.push(i);
874      }
875
876      assert_eq!(secure.len(), 10);
877
878      secure.unlock_slice(|slice| {
879         assert_eq!(slice, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
880      });
881   }
882
883   #[test]
884   fn test_reserve() {
885      let mut secure: SecureVec<u8> = SecureVec::new().unwrap();
886      secure.reserve(10);
887      assert_eq!(secure.capacity, 10);
888   }
889
890   #[test]
891   fn test_reserve_doubling() {
892      let mut secure: SecureVec<u8> = SecureVec::new().unwrap();
893      secure.reserve(10);
894
895      for i in 0..9 {
896         secure.push(i);
897      }
898
899      secure.push(9);
900      assert_eq!(secure.capacity, 10);
901      assert_eq!(secure.len(), 10);
902
903      secure.push(10);
904      assert_eq!(secure.capacity, 20);
905      assert_eq!(secure.len(), 11);
906   }
907
908   #[test]
909   fn test_index() {
910      let vec: Vec<u8> = vec![1, 2, 3];
911      let secure = SecureVec::from_vec(vec).unwrap();
912      secure.unlock(|secure| {
913         assert_eq!(secure[0], 1);
914         assert_eq!(secure[1], 2);
915         assert_eq!(secure[2], 3);
916      });
917   }
918
919   #[test]
920   fn test_unlock_slice() {
921      let vec: Vec<u8> = vec![1, 2, 3];
922      let secure = SecureVec::from_vec(vec).unwrap();
923      secure.unlock_slice(|slice| {
924         assert_eq!(slice, &[1, 2, 3]);
925      });
926   }
927
928   #[test]
929   fn test_unlock_slice_mut() {
930      let vec: Vec<u8> = vec![1, 2, 3];
931      let mut secure = SecureVec::from_vec(vec).unwrap();
932
933      secure.unlock_slice_mut(|slice| {
934         slice[0] = 4;
935         assert_eq!(slice, &mut [4, 2, 3]);
936      });
937   }
938
939   #[test]
940   fn test_unlock_iter() {
941      let vec: Vec<u8> = vec![1, 2, 3];
942      let secure = SecureVec::from_vec(vec).unwrap();
943      let sum: u8 = secure.unlock_iter(|iter| iter.map(|&x| x).sum());
944
945      assert_eq!(sum, 6);
946
947      let secure: SecureVec<u8> = SecureVec::new_with_capacity(3).unwrap();
948      let sum: u8 = secure.unlock_iter(|iter| iter.map(|&x| x).sum());
949
950      assert_eq!(sum, 0);
951   }
952
953   #[test]
954   fn test_unlock_iter_mut() {
955      let vec: Vec<u8> = vec![1, 2, 3];
956      let mut secure = SecureVec::from_vec(vec).unwrap();
957      secure.unlock_iter_mut(|iter| {
958         for elem in iter {
959            *elem += 1;
960         }
961      });
962
963      secure.unlock_slice(|slice| {
964         assert_eq!(slice, &[2, 3, 4]);
965      });
966   }
967
968   #[test]
969   fn test_index_should_fail_when_locked() {
970      let arg = "CRASH_TEST_SECUREVEC_LOCKED";
971
972      if std::env::args().any(|a| a == arg) {
973         let vec: Vec<u8> = vec![1, 2, 3];
974         let secure = SecureVec::from_vec(vec).unwrap();
975         let _value = core::hint::black_box(secure[0]);
976
977         std::process::exit(1);
978      }
979
980      let child = Command::new(std::env::current_exe().unwrap())
981         .arg("vec::tests::test_index_should_fail_when_locked")
982         .arg(arg)
983         .arg("--nocapture")
984         .stdout(Stdio::piped())
985         .stderr(Stdio::piped())
986         .spawn()
987         .expect("Failed to spawn child process");
988
989      let output = child.wait_with_output().expect("Failed to wait on child");
990      let status = output.status;
991
992      assert!(
993         !status.success(),
994         "Process exited successfully with code {:?}, but it should have crashed.",
995         status.code()
996      );
997
998      #[cfg(unix)]
999      {
1000         use std::os::unix::process::ExitStatusExt;
1001         let signal = status
1002            .signal()
1003            .expect("Process was not terminated by a signal on Unix.");
1004         assert!(
1005            signal == libc::SIGSEGV || signal == libc::SIGBUS,
1006            "Process terminated with unexpected signal: {}",
1007            signal
1008         );
1009         println!(
1010            "Test passed: Process correctly terminated with signal {}.",
1011            signal
1012         );
1013      }
1014
1015      #[cfg(windows)]
1016      {
1017         const STATUS_ACCESS_VIOLATION: i32 = 0xC0000005_u32 as i32;
1018         assert_eq!(
1019            status.code(),
1020            Some(STATUS_ACCESS_VIOLATION),
1021            "Process exited with unexpected code: {:x?}. Expected STATUS_ACCESS_VIOLATION.",
1022            status.code()
1023         );
1024         eprintln!("Test passed: Process correctly terminated with STATUS_ACCESS_VIOLATION.");
1025      }
1026   }
1027}