secure_types/
vec.rs

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