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