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