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
23pub 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 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 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 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 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 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 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 }
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 }
266 }
267
268 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 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 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 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 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 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 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 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 pub fn reserve(&mut self, additional: usize) {
382 if self.len() + additional <= self.capacity {
383 return;
384 }
385
386 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 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 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 self.ptr = new_ptr;
423 self.capacity = new_capacity;
424 self.lock_memory();
425 }
426
427 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
562pub 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, tail_len: usize, _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 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 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 let new_len = self.drain_start_index + self.tail_len;
628
629 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 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 ptr::drop_in_place(current_cleanup_ptr);
656 }
657 }
660
661 (*current_cleanup_ptr).zeroize();
663 current_cleanup_ptr = current_cleanup_ptr.add(1);
664 }
665
666 self.vec_ref.len = new_len;
668
669 self.vec_ref.lock_memory();
671 }
672 }
673}
674
675fn 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 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}