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
23pub 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 pub fn new() -> Result<Self, Error> {
98 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 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 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 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 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 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 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 }
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) }
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) }
367 }
368
369 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 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 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 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 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 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 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 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 pub fn reserve(&mut self, additional: usize) {
483 if self.len() + additional <= self.capacity {
484 return;
485 }
486
487 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 #[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 unsafe {
515 self.unlock_memory();
516 core::ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_ptr, self.len());
517
518 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 self.ptr = NonNull::new(new_ptr).expect("New pointer was null");
538 self.capacity = new_capacity;
539 self.lock_memory();
540 }
541
542 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 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
679pub 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, tail_len: usize, _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 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 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 let new_len = self.drain_start_index + self.tail_len;
745
746 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 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 ptr::drop_in_place(current_cleanup_ptr);
773 }
774 }
777
778 (*current_cleanup_ptr).zeroize();
780 current_cleanup_ptr = current_cleanup_ptr.add(1);
781 }
782
783 self.vec_ref.len = new_len;
785
786 self.vec_ref.lock_memory();
788 }
789 }
790}
791
792fn 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 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}