1#[cfg(not(feature = "use_os"))]
2use alloc::{Layout, alloc, dealloc};
3
4#[cfg(feature = "use_os")]
5use std::vec::Vec;
6
7use super::{Error, SecureArray};
8use core::{
9 marker::PhantomData,
10 mem,
11 ops::{Bound, RangeBounds},
12 ptr::{self, NonNull},
13};
14use zeroize::{DefaultIsZeroes, Zeroize};
15
16#[cfg(feature = "use_os")]
17use super::{alloc_aligned, free, page_aligned_size};
18#[cfg(feature = "use_os")]
19use memsec::Prot;
20
21pub type SecureBytes = SecureVec<u8>;
22
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 pub fn new() -> Result<Self, Error> {
97 let capacity = 1;
99 let size = capacity * mem::size_of::<T>();
100 let ptr = unsafe { alloc_aligned::<T>(size)? };
101
102 let secure = SecureVec {
103 ptr,
104 len: 0,
105 capacity,
106 _marker: PhantomData,
107 };
108
109 let (encrypted, locked) = secure.lock_memory();
110
111 #[cfg(feature = "use_os")]
112 if !locked {
113 return Err(Error::LockFailed);
114 }
115
116 #[cfg(feature = "use_os")]
117 if !encrypted {
118 return Err(Error::CryptProtectMemoryFailed);
119 }
120
121 Ok(secure)
122 }
123
124 pub fn new_with_capacity(mut capacity: usize) -> Result<Self, Error> {
126 if capacity == 0 {
127 capacity = 1;
128 }
129
130 let size = capacity * mem::size_of::<T>();
131 let ptr = unsafe { alloc_aligned::<T>(size)? };
132
133 let secure = SecureVec {
134 ptr,
135 len: 0,
136 capacity,
137 _marker: PhantomData,
138 };
139
140 let (encrypted, locked) = secure.lock_memory();
141
142 #[cfg(feature = "use_os")]
143 if !locked {
144 return Err(Error::LockFailed);
145 }
146
147 #[cfg(feature = "use_os")]
148 if !encrypted {
149 return Err(Error::CryptProtectMemoryFailed);
150 }
151
152 Ok(secure)
153 }
154
155 #[cfg(feature = "use_os")]
156 pub fn from_vec(mut vec: Vec<T>) -> Result<Self, Error> {
160 if vec.capacity() == 0 {
161 vec.reserve(1);
162 }
163
164 let capacity = vec.capacity();
165 let len = vec.len();
166
167 let size = capacity * mem::size_of::<T>();
168
169 let ptr = match unsafe { alloc_aligned::<T>(size) } {
170 Ok(ptr) => ptr,
171 Err(_) => {
172 vec.zeroize();
173 return Err(Error::AllocationFailed);
174 }
175 };
176
177 unsafe {
179 core::ptr::copy_nonoverlapping(vec.as_ptr(), ptr.as_ptr() as *mut T, len);
180 }
181
182 vec.zeroize();
183
184 let secure = SecureVec {
185 ptr,
186 len,
187 capacity,
188 _marker: PhantomData,
189 };
190
191 let (encrypted, locked) = secure.lock_memory();
192
193 if !locked {
194 return Err(Error::LockFailed);
195 }
196
197 if !encrypted {
198 return Err(Error::CryptProtectMemoryFailed);
199 }
200
201 Ok(secure)
202 }
203
204 pub fn from_slice_mut(slice: &mut [T]) -> Result<Self, Error>
208 where
209 T: Clone + DefaultIsZeroes,
210 {
211 let mut secure_vec = SecureVec::new_with_capacity(slice.len())?;
212 secure_vec.len = slice.len();
213 secure_vec.unlock_slice_mut(|dest_slice| {
214 dest_slice.clone_from_slice(slice);
215 });
216 slice.zeroize();
217 Ok(secure_vec)
218 }
219
220 pub fn from_slice(slice: &[T]) -> Result<Self, Error>
224 where
225 T: Clone,
226 {
227 let mut secure_vec = SecureVec::new_with_capacity(slice.len())?;
228 secure_vec.len = slice.len();
229 secure_vec.unlock_slice_mut(|dest_slice| {
230 dest_slice.clone_from_slice(slice);
231 });
232 Ok(secure_vec)
233 }
234
235 pub fn len(&self) -> usize {
236 self.len
237 }
238
239 pub fn is_empty(&self) -> bool {
240 self.len() == 0
241 }
242
243 pub fn as_ptr(&self) -> *const T {
244 self.ptr.as_ptr()
245 }
246
247 pub fn as_mut_ptr(&mut self) -> *mut u8 {
248 self.ptr.as_ptr() as *mut u8
249 }
250
251 #[allow(dead_code)]
252 fn aligned_size(&self) -> usize {
253 let size = self.capacity * mem::size_of::<T>();
254 #[cfg(feature = "use_os")]
255 {
256 unsafe { page_aligned_size(size) }
257 }
258 #[cfg(not(feature = "use_os"))]
259 {
260 size }
262 }
263
264 #[cfg(all(feature = "use_os", windows))]
265 fn encypt_memory(&self) -> bool {
266 let ptr = self.as_ptr() as *mut u8;
267 super::crypt_protect_memory(ptr, self.aligned_size())
268 }
269
270 #[cfg(all(feature = "use_os", windows))]
271 fn decrypt_memory(&self) -> bool {
272 let ptr = self.as_ptr() as *mut u8;
273 super::crypt_unprotect_memory(ptr, self.aligned_size())
274 }
275
276 pub(crate) fn lock_memory(&self) -> (bool, bool) {
277 #[cfg(feature = "use_os")]
278 {
279 #[cfg(windows)]
280 {
281 let encrypt_ok = self.encypt_memory();
282 let mprotect_ok = super::mprotect(self.ptr, Prot::NoAccess);
283 (encrypt_ok, mprotect_ok)
284 }
285 #[cfg(unix)]
286 {
287 let mprotect_ok = super::mprotect(self.ptr, Prot::NoAccess);
288 (true, mprotect_ok)
289 }
290 }
291 #[cfg(not(feature = "use_os"))]
292 {
293 (true, true) }
295 }
296
297 pub(crate) fn unlock_memory(&self) -> (bool, bool) {
298 #[cfg(feature = "use_os")]
299 {
300 #[cfg(windows)]
301 {
302 let mprotect_ok = super::mprotect(self.ptr, Prot::ReadWrite);
303 if !mprotect_ok {
304 return (false, false);
305 }
306 let decrypt_ok = self.decrypt_memory();
307 (decrypt_ok, mprotect_ok)
308 }
309 #[cfg(unix)]
310 {
311 let mprotect_ok = super::mprotect(self.ptr, Prot::ReadWrite);
312 (true, mprotect_ok)
313 }
314 }
315
316 #[cfg(not(feature = "use_os"))]
317 {
318 (true, true) }
320 }
321
322 pub fn unlock<F, R>(&self, f: F) -> R
324 where
325 F: FnOnce(&SecureVec<T>) -> R,
326 {
327 self.unlock_memory();
328 let result = f(self);
329 self.lock_memory();
330 result
331 }
332
333 pub fn unlock_slice<F, R>(&self, f: F) -> R
335 where
336 F: FnOnce(&[T]) -> R,
337 {
338 unsafe {
339 self.unlock_memory();
340 let slice = core::slice::from_raw_parts(self.ptr.as_ptr(), self.len);
341 let result = f(slice);
342 self.lock_memory();
343 result
344 }
345 }
346
347 pub fn unlock_slice_mut<F, R>(&mut self, f: F) -> R
349 where
350 F: FnOnce(&mut [T]) -> R,
351 {
352 unsafe {
353 self.unlock_memory();
354 let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
355 let result = f(slice);
356 self.lock_memory();
357 result
358 }
359 }
360
361 pub fn unlock_iter<F, R>(&self, f: F) -> R
363 where
364 F: FnOnce(core::slice::Iter<T>) -> R,
365 {
366 unsafe {
367 self.unlock_memory();
368 let slice = core::slice::from_raw_parts(self.ptr.as_ptr(), self.len);
369 let iter = slice.iter();
370 let result = f(iter);
371 self.lock_memory();
372 result
373 }
374 }
375
376 pub fn unlock_iter_mut<F, R>(&mut self, f: F) -> R
378 where
379 F: FnOnce(core::slice::IterMut<T>) -> R,
380 {
381 unsafe {
382 self.unlock_memory();
383 let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
384 let iter = slice.iter_mut();
385 let result = f(iter);
386 self.lock_memory();
387 result
388 }
389 }
390
391 pub fn erase(&mut self) {
395 unsafe {
396 self.unlock_memory();
397 let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
398 for elem in slice.iter_mut() {
399 elem.zeroize();
400 }
401 self.clear();
402 self.lock_memory();
403 }
404 }
405
406 pub fn clear(&mut self) {
410 self.len = 0;
411 }
412
413 pub fn push(&mut self, value: T) {
414 self.reserve(1);
415
416 self.unlock_memory();
417
418 unsafe {
419 core::ptr::write(self.ptr.as_ptr().add(self.len), value);
421
422 self.len += 1;
423 }
424
425 self.lock_memory();
426 }
427
428 pub fn reserve(&mut self, additional: usize) {
436 if self.len() + additional <= self.capacity {
437 return;
438 }
439
440 let required_capacity = self.len() + additional;
442 let new_capacity = (self.capacity.max(1) * 2).max(required_capacity);
443
444 let new_size = new_capacity * mem::size_of::<T>();
445 let new_ptr = unsafe { alloc_aligned::<T>(new_size).expect("Allocation failed") };
446
447 unsafe {
449 self.unlock_memory();
450 core::ptr::copy_nonoverlapping(
451 self.ptr.as_ptr(),
452 new_ptr.as_ptr() as *mut T,
453 self.len(),
454 );
455
456 if self.capacity > 0 {
458 let slice = core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len);
459 for elem in slice.iter_mut() {
460 elem.zeroize();
461 }
462 }
463
464 #[cfg(feature = "use_os")]
465 free(self.ptr);
466
467 #[cfg(not(feature = "use_os"))]
468 {
469 let old_size = self.capacity * mem::size_of::<T>();
470 let old_layout = Layout::from_size_align_unchecked(old_size, mem::align_of::<T>());
471 dealloc(self.ptr.as_ptr() as *mut u8, old_layout);
472 }
473 }
474
475 self.ptr = new_ptr;
477 self.capacity = new_capacity;
478 self.lock_memory();
479 }
480
481 pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
491 where
492 R: RangeBounds<usize>,
493 {
494 self.unlock_memory();
495
496 let original_len = self.len;
497
498 let (drain_start_idx, drain_end_idx) = resolve_range_indices(range, original_len);
499
500 let tail_len = original_len - drain_end_idx;
501
502 self.len = drain_start_idx;
503
504 Drain {
505 vec_ref: self,
506 drain_start_index: drain_start_idx,
507 current_drain_iter_index: drain_start_idx,
508 drain_end_index: drain_end_idx,
509 original_vec_len: original_len,
510 tail_len,
511 _marker: PhantomData,
512 }
513 }
514}
515
516impl<T: Clone + Zeroize> Clone for SecureVec<T> {
517 fn clone(&self) -> Self {
518 let mut new_vec = SecureVec::new_with_capacity(self.capacity).unwrap();
519 new_vec.len = self.len;
520
521 self.unlock_slice(|src_slice| {
522 new_vec.unlock_slice_mut(|dest_slice| {
523 dest_slice.clone_from_slice(src_slice);
524 });
525 });
526
527 new_vec
528 }
529}
530
531impl<const LENGTH: usize> From<SecureArray<u8, LENGTH>> for SecureVec<u8> {
532 fn from(array: SecureArray<u8, LENGTH>) -> Self {
533 let mut new_vec = SecureVec::new_with_capacity(LENGTH)
534 .expect("Failed to allocate SecureVec during conversion");
535 new_vec.len = array.len();
536
537 array.unlock(|array_slice| {
538 new_vec.unlock_slice_mut(|vec_slice| {
539 vec_slice.copy_from_slice(array_slice);
540 });
541 });
542
543 new_vec
544 }
545}
546
547impl<T: Zeroize> Drop for SecureVec<T> {
548 fn drop(&mut self) {
549 self.erase();
550 self.unlock_memory();
551
552 #[cfg(feature = "use_os")]
553 free(self.ptr);
554
555 #[cfg(not(feature = "use_os"))]
556 {
557 let layout =
558 Layout::from_size_align_unchecked(self.allocated_byte_size(), mem::align_of::<T>());
559 dealloc(self.ptr.as_ptr() as *mut u8, layout);
560 }
561 }
562}
563
564impl<T: Zeroize> core::ops::Index<usize> for SecureVec<T> {
565 type Output = T;
566
567 fn index(&self, index: usize) -> &Self::Output {
568 assert!(index < self.len, "Index out of bounds");
569 unsafe {
570 let ptr = self.ptr.as_ptr().add(index);
571 &*ptr
572 }
573 }
574}
575
576#[cfg(feature = "serde")]
577impl serde::Serialize for SecureVec<u8> {
578 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
579 where
580 S: serde::Serializer,
581 {
582 self.unlock_slice(|slice| serializer.collect_seq(slice.iter()))
583 }
584}
585
586#[cfg(feature = "serde")]
587impl<'de> serde::Deserialize<'de> for SecureVec<u8> {
588 fn deserialize<D>(deserializer: D) -> Result<SecureVec<u8>, D::Error>
589 where
590 D: serde::Deserializer<'de>,
591 {
592 struct SecureVecVisitor;
593 impl<'de> serde::de::Visitor<'de> for SecureVecVisitor {
594 type Value = SecureVec<u8>;
595 fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
596 write!(formatter, "a sequence of bytes")
597 }
598 fn visit_seq<A>(
599 self,
600 mut seq: A,
601 ) -> Result<<Self as serde::de::Visitor<'de>>::Value, A::Error>
602 where
603 A: serde::de::SeqAccess<'de>,
604 {
605 let mut vec = Vec::new();
606 while let Some(byte) = seq.next_element::<u8>()? {
607 vec.push(byte);
608 }
609 SecureVec::from_vec(vec).map_err(serde::de::Error::custom)
610 }
611 }
612 deserializer.deserialize_seq(SecureVecVisitor)
613 }
614}
615
616pub struct Drain<'a, T: Zeroize + 'a> {
624 vec_ref: &'a mut SecureVec<T>,
625 drain_start_index: usize,
626 current_drain_iter_index: usize,
627 drain_end_index: usize,
628
629 original_vec_len: usize, tail_len: usize, _marker: PhantomData<&'a T>,
633}
634
635impl<'a, T: Zeroize> Iterator for Drain<'a, T> {
636 type Item = T;
637
638 fn next(&mut self) -> Option<T> {
639 if self.current_drain_iter_index < self.drain_end_index {
640 unsafe {
642 let item_ptr = self.vec_ref.ptr.as_ptr().add(self.current_drain_iter_index);
643 let item = ptr::read(item_ptr);
644 self.current_drain_iter_index += 1;
645 Some(item)
646 }
647 } else {
648 None
649 }
650 }
651
652 fn size_hint(&self) -> (usize, Option<usize>) {
653 let remaining = self.drain_end_index - self.current_drain_iter_index;
654 (remaining, Some(remaining))
655 }
656}
657
658impl<'a, T: Zeroize> ExactSizeIterator for Drain<'a, T> {}
659
660impl<'a, T: Zeroize> Drop for Drain<'a, T> {
661 fn drop(&mut self) {
662 unsafe {
663 if mem::needs_drop::<T>() {
665 let mut current_ptr = self.vec_ref.ptr.as_ptr().add(self.current_drain_iter_index);
666 let end_ptr = self.vec_ref.ptr.as_ptr().add(self.drain_end_index);
667 while current_ptr < end_ptr {
668 ptr::drop_in_place(current_ptr);
669 current_ptr = current_ptr.add(1);
670 }
671 }
672
673 let hole_dst_ptr = self.vec_ref.ptr.as_ptr().add(self.drain_start_index);
674 let tail_src_ptr = self.vec_ref.ptr.as_ptr().add(self.drain_end_index);
675
676 if self.tail_len > 0 {
677 ptr::copy(tail_src_ptr, hole_dst_ptr, self.tail_len);
678 }
679
680 let new_len = self.drain_start_index + self.tail_len;
682
683 let mut current_cleanup_ptr = self.vec_ref.ptr.as_ptr().add(new_len);
693 let end_cleanup_ptr = self.vec_ref.ptr.as_ptr().add(self.original_vec_len);
694
695 let original_tail_start_ptr_val = tail_src_ptr as usize;
697
698 while current_cleanup_ptr < end_cleanup_ptr {
699 if mem::needs_drop::<T>() {
700 let current_ptr_val = current_cleanup_ptr as usize;
701 let original_tail_end_ptr_val =
702 original_tail_start_ptr_val + self.tail_len * mem::size_of::<T>();
703
704 if current_ptr_val >= original_tail_start_ptr_val
705 && current_ptr_val < original_tail_end_ptr_val
706 {
707 ptr::drop_in_place(current_cleanup_ptr);
710 }
711 }
714
715 (*current_cleanup_ptr).zeroize();
717 current_cleanup_ptr = current_cleanup_ptr.add(1);
718 }
719
720 self.vec_ref.len = new_len;
722
723 self.vec_ref.lock_memory();
725 }
726 }
727}
728
729fn resolve_range_indices<R: RangeBounds<usize>>(range: R, len: usize) -> (usize, usize) {
731 let start_bound = range.start_bound();
732 let end_bound = range.end_bound();
733
734 let start = match start_bound {
735 Bound::Included(&s) => s,
736 Bound::Excluded(&s) => s
737 .checked_add(1)
738 .unwrap_or_else(|| panic!("attempted to start drain at Excluded(usize::MAX)")),
739 Bound::Unbounded => 0,
740 };
741
742 let end = match end_bound {
743 Bound::Included(&e) => e
744 .checked_add(1)
745 .unwrap_or_else(|| panic!("attempted to end drain at Included(usize::MAX)")),
746 Bound::Excluded(&e) => e,
747 Bound::Unbounded => len,
748 };
749
750 if start > end {
751 panic!(
752 "drain range start ({}) must be less than or equal to end ({})",
753 start, end
754 );
755 }
756 if end > len {
757 panic!(
758 "drain range end ({}) out of bounds for slice of length {}",
759 end, len
760 );
761 }
762
763 (start, end)
764}
765
766#[cfg(all(test, feature = "use_os"))]
767mod tests {
768 use super::*;
769 use std::process::{Command, Stdio};
770 use std::sync::{Arc, Mutex};
771
772 #[test]
773 fn test_creation() {
774 let vec: Vec<u8> = vec![1, 2, 3];
775 let secure_vec = SecureVec::from_vec(vec).unwrap();
776
777 secure_vec.unlock_slice(|slice| {
778 assert_eq!(slice, &[1, 2, 3]);
779 });
780
781 let exposed_slice = &mut [1, 2, 3];
782 let secure_slice = SecureVec::from_slice_mut(exposed_slice).unwrap();
783 assert_eq!(exposed_slice, &[0u8; 3]);
784
785 secure_slice.unlock_slice(|slice| {
786 assert_eq!(slice, &[1, 2, 3]);
787 });
788
789 let exposed_slice = [1, 2, 3];
790 let secure_slice = SecureVec::from_slice(&exposed_slice).unwrap();
791
792 secure_slice.unlock_slice(|slice| {
793 assert_eq!(slice, exposed_slice);
794 });
795 }
796
797 #[test]
798 fn test_from_secure_array() {
799 let exposed: &mut [u8; 3] = &mut [1, 2, 3];
800 let array: SecureArray<u8, 3> = SecureArray::from_slice_mut(exposed).unwrap();
801 let vec: SecureVec<u8> = array.into();
802 assert_eq!(vec.len(), 3);
803 vec.unlock_slice(|slice| {
804 assert_eq!(slice, &[1, 2, 3]);
805 });
806 }
807
808 #[test]
809 fn test_size_cannot_be_zero() {
810 let secure: SecureVec<u8> = SecureVec::new().unwrap();
811 let size = secure.aligned_size();
812 assert_eq!(size > 0, true);
813
814 let secure: SecureVec<u8> = SecureVec::from_vec(vec![]).unwrap();
815 let size = secure.aligned_size();
816 assert_eq!(size > 0, true);
817
818 let secure: SecureVec<u8> = SecureVec::new_with_capacity(0).unwrap();
819 let size = secure.aligned_size();
820 assert_eq!(size > 0, true);
821 }
822
823 #[test]
824 fn lock_unlock_works() {
825 let secure: SecureVec<u8> = SecureVec::new().unwrap();
826
827 let (decrypted, unlocked) = secure.unlock_memory();
828 assert!(decrypted);
829 assert!(unlocked);
830
831 let (encrypted, locked) = secure.lock_memory();
832 assert!(encrypted);
833 assert!(locked);
834 }
835
836 #[test]
837 fn test_thread_safety() {
838 let vec: Vec<u8> = vec![];
839 let secure = SecureVec::from_vec(vec).unwrap();
840 let secure = Arc::new(Mutex::new(secure));
841
842 let mut handles = Vec::new();
843 for i in 0..5u8 {
844 let secure_clone = secure.clone();
845 let handle = std::thread::spawn(move || {
846 let mut secure = secure_clone.lock().unwrap();
847 secure.push(i);
848 });
849 handles.push(handle);
850 }
851
852 for handle in handles {
853 handle.join().unwrap();
854 }
855
856 let mut sec = secure.lock().unwrap();
857 sec.unlock_slice_mut(|slice| {
858 slice.sort();
859 assert_eq!(slice.len(), 5);
860 assert_eq!(slice, &[0, 1, 2, 3, 4]);
861 });
862 }
863
864 #[test]
865 fn test_clone() {
866 let vec: Vec<u8> = vec![1, 2, 3];
867 let secure1 = SecureVec::from_vec(vec).unwrap();
868 let secure2 = secure1.clone();
869
870 secure1.unlock_slice(|slice| {
871 secure2.unlock_slice(|slice2| {
872 assert_eq!(slice, slice2);
873 });
874 });
875 }
876
877 #[test]
878 fn test_do_not_call_forget_on_drain() {
879 let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
880 let mut secure = SecureVec::from_vec(vec).unwrap();
881 let drain = secure.drain(..3);
882 core::mem::forget(drain);
883 secure.unlock_slice(|secure| {
885 assert_eq!(secure.len(), 0);
886 });
887 }
888
889 #[test]
890 fn test_drain() {
891 let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
892 let mut secure = SecureVec::from_vec(vec).unwrap();
893 let mut drain = secure.drain(..3);
894 assert_eq!(drain.next(), Some(1));
895 assert_eq!(drain.next(), Some(2));
896 assert_eq!(drain.next(), Some(3));
897 assert_eq!(drain.next(), None);
898 drop(drain);
899 secure.unlock_slice(|secure| {
900 assert_eq!(secure.len(), 7);
901 assert_eq!(secure, &[4, 5, 6, 7, 8, 9, 10]);
902 });
903 }
904
905 #[cfg(feature = "serde")]
906 #[test]
907 fn test_secure_vec_serde() {
908 let vec: Vec<u8> = vec![1, 2, 3];
909 let secure = SecureVec::from_vec(vec).unwrap();
910 let json = serde_json::to_vec(&secure).expect("Serialization failed");
911 let deserialized: SecureVec<u8> =
912 serde_json::from_slice(&json).expect("Deserialization failed");
913 deserialized.unlock_slice(|slice| {
914 assert_eq!(slice, &[1, 2, 3]);
915 });
916 }
917
918 #[test]
919 fn test_erase() {
920 let vec: Vec<u8> = vec![1, 2, 3];
921 let mut secure = SecureVec::from_vec(vec).unwrap();
922 secure.erase();
923
924 secure.unlock(|secure| {
925 assert_eq!(secure.len, 0);
926 assert_eq!(secure.capacity, 3);
927 });
928
929 secure.unlock_iter(|iter| {
930 for elem in iter {
931 assert_eq!(elem, &0);
932 }
933 });
934 }
935
936 #[test]
937 fn test_push() {
938 let vec: Vec<u8> = Vec::new();
939 let mut secure = SecureVec::from_vec(vec).unwrap();
940 for i in 0..10 {
941 secure.push(i);
942 }
943
944 assert_eq!(secure.len(), 10);
945
946 secure.unlock_slice(|slice| {
947 assert_eq!(slice, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
948 });
949 }
950
951 #[test]
952 fn test_reserve() {
953 let mut secure: SecureVec<u8> = SecureVec::new().unwrap();
954 secure.reserve(10);
955 assert_eq!(secure.capacity, 10);
956 }
957
958 #[test]
959 fn test_reserve_doubling() {
960 let mut secure: SecureVec<u8> = SecureVec::new().unwrap();
961 secure.reserve(10);
962
963 for i in 0..9 {
964 secure.push(i);
965 }
966
967 secure.push(9);
968 assert_eq!(secure.capacity, 10);
969 assert_eq!(secure.len(), 10);
970
971 secure.push(10);
972 assert_eq!(secure.capacity, 20);
973 assert_eq!(secure.len(), 11);
974 }
975
976 #[test]
977 fn test_index() {
978 let vec: Vec<u8> = vec![1, 2, 3];
979 let secure = SecureVec::from_vec(vec).unwrap();
980 secure.unlock(|secure| {
981 assert_eq!(secure[0], 1);
982 assert_eq!(secure[1], 2);
983 assert_eq!(secure[2], 3);
984 });
985 }
986
987 #[test]
988 fn test_unlock_slice() {
989 let vec: Vec<u8> = vec![1, 2, 3];
990 let secure = SecureVec::from_vec(vec).unwrap();
991 secure.unlock_slice(|slice| {
992 assert_eq!(slice, &[1, 2, 3]);
993 });
994 }
995
996 #[test]
997 fn test_unlock_slice_mut() {
998 let vec: Vec<u8> = vec![1, 2, 3];
999 let mut secure = SecureVec::from_vec(vec).unwrap();
1000
1001 secure.unlock_slice_mut(|slice| {
1002 slice[0] = 4;
1003 assert_eq!(slice, &mut [4, 2, 3]);
1004 });
1005 }
1006
1007 #[test]
1008 fn test_unlock_iter() {
1009 let vec: Vec<u8> = vec![1, 2, 3];
1010 let secure = SecureVec::from_vec(vec).unwrap();
1011 let sum: u8 = secure.unlock_iter(|iter| iter.map(|&x| x).sum());
1012
1013 assert_eq!(sum, 6);
1014
1015 let secure: SecureVec<u8> = SecureVec::new_with_capacity(3).unwrap();
1016 let sum: u8 = secure.unlock_iter(|iter| iter.map(|&x| x).sum());
1017
1018 assert_eq!(sum, 0);
1019 }
1020
1021 #[test]
1022 fn test_unlock_iter_mut() {
1023 let vec: Vec<u8> = vec![1, 2, 3];
1024 let mut secure = SecureVec::from_vec(vec).unwrap();
1025 secure.unlock_iter_mut(|iter| {
1026 for elem in iter {
1027 *elem += 1;
1028 }
1029 });
1030
1031 secure.unlock_slice(|slice| {
1032 assert_eq!(slice, &[2, 3, 4]);
1033 });
1034 }
1035
1036 #[test]
1037 fn test_index_should_fail_when_locked() {
1038 let arg = "CRASH_TEST_SECUREVEC_LOCKED";
1039
1040 if std::env::args().any(|a| a == arg) {
1041 let vec: Vec<u8> = vec![1, 2, 3];
1042 let secure = SecureVec::from_vec(vec).unwrap();
1043 let _value = core::hint::black_box(secure[0]);
1044
1045 std::process::exit(1);
1046 }
1047
1048 let child = Command::new(std::env::current_exe().unwrap())
1049 .arg("vec::tests::test_index_should_fail_when_locked")
1050 .arg(arg)
1051 .arg("--nocapture")
1052 .stdout(Stdio::piped())
1053 .stderr(Stdio::piped())
1054 .spawn()
1055 .expect("Failed to spawn child process");
1056
1057 let output = child.wait_with_output().expect("Failed to wait on child");
1058 let status = output.status;
1059
1060 assert!(
1061 !status.success(),
1062 "Process exited successfully with code {:?}, but it should have crashed.",
1063 status.code()
1064 );
1065
1066 #[cfg(unix)]
1067 {
1068 use std::os::unix::process::ExitStatusExt;
1069 let signal = status
1070 .signal()
1071 .expect("Process was not terminated by a signal on Unix.");
1072 assert!(
1073 signal == libc::SIGSEGV || signal == libc::SIGBUS,
1074 "Process terminated with unexpected signal: {}",
1075 signal
1076 );
1077 println!(
1078 "Test passed: Process correctly terminated with signal {}.",
1079 signal
1080 );
1081 }
1082
1083 #[cfg(windows)]
1084 {
1085 const STATUS_ACCESS_VIOLATION: i32 = 0xC0000005_u32 as i32;
1086 assert_eq!(
1087 status.code(),
1088 Some(STATUS_ACCESS_VIOLATION),
1089 "Process exited with unexpected code: {:x?}. Expected STATUS_ACCESS_VIOLATION.",
1090 status.code()
1091 );
1092 eprintln!("Test passed: Process correctly terminated with STATUS_ACCESS_VIOLATION.");
1093 }
1094 }
1095}